繁体   English   中英

c,共享库中的c ++内存

[英]c, c++ memory in shared libraries

我不确定如何在DLL和共享对象中管理静态全局内存。 我不知道每个人在不同平台上是以相同的方式还是以不同的方式处理它。

考虑您有一个类库,其中一个类是互斥锁类,并且库中的其他类将使用该互斥锁。 在库中分配互斥体的最佳或最安全的方法是什么? 我可以看到几个选择:

  1. 在课程中将互斥锁设为私有。 我看不到这起作用,因为互斥锁寿命仅在对象的生存期内有效。 我不确定是否可以使对象成为单例并在加载库时初始化它(使用dllattach或属性 ((constructor)))。

  2. 在类的外部在库的静态全局空间中分配互斥量。 我认为这将是最好的选择,但是在加载DLL时究竟会发生什么? 如果我在库中将对象设为静态和全局对象,什么时候分配它,在程序中哪里分配它? 如果在运行时而不是程序启动时加载库,会发生什么情况?

非常感谢有关此的任何信息!

在共享映像中管理内存的方式取决于特定的平台,并且DLL特定于Microsoft Windows。

通常, 您应该始终避免使用全局/共享静态变量 ,因为它们可能会引入严重的问题或难以识别或解决的错误。 甚至单例类也可能在C ++中引起一些问题 ,尤其是在库或多线程应用程序中。 (通常,即使在高级语言中,使用单例也不被认为是好的 。)

为了防止相互排斥的竞争情况,最好的选择是使用通过RAII技术实现的范围锁类,以及shared_ptr 智能指针 ,该指针自动执行内存分配和取消分配。

下面的代码说明了如何使用Windows API和上述技术(以及Pimpl习惯用法 )实现Mutex

// Mutex.h
#pragma once
#include <memory>

class Mutex
{
public:
    typedef unsigned long milliseconds;

    Mutex();
    ~Mutex();

    void Lock();
    void Unlock();
    bool TryLock();
    bool TimedLock(milliseconds ms);

private:
    struct private_data;
    std::shared_ptr<private_data> data;
    // Actual data is hold in private_data struct which is non-accessible.
    // We only hold a "copyable handle" to it through the shared_ptr, which 
    // prevents copying this "actual data" object by, say, assignment operators.
    // So, private_data's destructor automatically gets called only when the last
    // Mutex object leaves its scope.
};


// Mutex.cpp
#include "Mutex.h"
#include <windows.h>

struct Mutex::private_data
{
    HANDLE hMutex;

    private_data()
    {
        hMutex = CreateMutex(NULL, FALSE, NULL);
    }

    ~private_data()
    {
        // Unlock(); ?? :/
        CloseHandle(hMutex);
    }
};

Mutex::Mutex()
    : data (new private_data())
{ }

Mutex::~Mutex()
{ }

void Mutex::Lock()
{
    DWORD ret = WaitForSingleObject(data->hMutex, INFINITE);
    ASSERT(ret == WAIT_OBJECT_0);
}

void Mutex::Unlock()
{
    ReleaseMutex(data->hMutex);
}

bool Mutex::TryLock()
{
    DWORD ret = WaitForSingleObject(data->hMutex, 0);

    ASSERT(ret != WAIT_ABANDONED);
    ASSERT(ret != WAIT_FAILED);

    return ret != WAIT_TIMEOUT;
}

bool Mutex::TimedLock(milliseconds ms)
{
    DWORD ret = WaitForSingleObject(data->hMutex, static_cast<DWORD>(ms));

    ASSERT(ret != WAIT_ABANDONED);
    ASSERT(ret != WAIT_FAILED);

    return ret != WAIT_TIMEOUT;
}


// ScopedLock.h
#pragma once
#include "Mutex.h"

class ScopedLock
{
private:
    Mutex& m_mutex;

    ScopedLock(ScopedLock const&);             // disable copy constructor
    ScopedLock& operator= (ScopedLock const&); // disable assignment operator

public:
    ScopedLock(Mutex& mutex)
        : m_mutex(mutex)
    { m_mutex.Lock(); }

    ~ScopedLock()
    { m_mutex.Unlock(); }
};

用法示例:

Mutex m1;
MyClass1 o1;
MyClass2 o2;
...

{
    ScopedLock lock(m1);

    // thread-safe operations
    o1.Decrease();
    o2.Increase();

} // lock is released automatically here upon leaving scope

// non-thread-safe operations
o1.Decrease();
o2.Increase();


尽管上面的代码将为您提供基本的思想,但更好的选择是使用诸如boost的高质量C ++库,该库具有mutexscoped_lock和许多其他可用的类。 (幸运的是,C ++ 11完全覆盖了同步类,使您不必使用boost库。)

更新:
我建议您搜索有关C ++自动垃圾收集以及RAII技术的主题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM