2013-10-05 109 views
1

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

考虑你有一个类库,其中一个类是一个互斥类,并且库中的其他类将使用该互斥量。什么是在图书馆分配互斥体的最好或最安全的方法?我可以看到几个选项:

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

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

任何有关这方面的信息,非常感谢!

+2

动态加载库不是C++标准的一部分,因此在运行时加载库的操作语义必须由平台指定。 –

回答

2

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

一般来说,你应该总是避免使用全局/共享静态变量,因为它们可能会引入严重的问题或错误,这些错误是难以识别或解决。即使是单例类也可能导致several issues in C++,特别是在库或多线程应用程序中。 (通常,采用单身are not considered good即使在更高层次的语言。)

对于防范互斥竞争条件,最好的办法是使用范围的锁类使用RAII technique实现的,旁边的shared_ptrsmart pointer,它会自动内存分配和解除分配。

在下面的代码说明了通过使用Windows API和上述技术实现Mutex(以及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(); 


虽然上面的代码将会给你的基本理念,甚至是更好的选择是使用像boost高品质的C++库,其中有已经上市mutex, scoped_lock和许多其他类。 (幸运的是C++ 11完全覆盖了同步类,使您不必使用boost库。)

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

+0

感谢您的信息,真的很好写 – kris