1

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

假设您有一个类库,其中一个类是互斥锁类,而库中的其他类将使用该互斥锁。在库中分配互斥锁的最佳或​​最安全的方法是什么?我可以看到几个选项:

  1. 在类中将互斥锁设为私有。这我看不到工作,因为互斥体生命只在对象的生命周期内有效。也许使对象成为单例并在加载库时初始化它(使用 dllattach 或属性((构造函数)))会起作用,我不确定。

  2. 在库的静态全局空间中分配类外部的互斥锁。我认为这将是最好的选择,但加载 DLL 时究竟会发生什么?如果我在库中创建了一个静态和全局对象,它何时被分配,它在程序中的哪个位置被分配?如果库是在运行时而不是程序启动时加载的,会发生什么?

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

4

1 回答 1

2

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

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

为了防止互斥竞争条件,最好的选择是使用使用RAII 技术实现的作用域锁类,以及智能指针,它可以自动分配和取消分配内存。shared_ptr

下面的代码说明Mutex了使用 Windows API 和上述技术(以及Pimpl idiom)实现:

// 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();


虽然上面的代码会给你基本的想法,但更好的选择是使用高质量的 C++ 库,比如boost,它有mutexscoped_lock以及许多其他已经可用的类。(幸运的是,C++11 完全覆盖了同步类,让您不必使用 boost 库。)

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

于 2013-10-05T13:31:54.983 回答