Gen*_*ent 6 c++ linux static locking shared-libraries
我需要编写加载共享库的类.dlopen()/ dlerror()序列需要锁定才能是线程安全的.
class LibLoader {
public:
LibLoader(string whichLib);
bool Load() { Wait(lock); ... dlopen() ... dlerror() ... }
bool Unload() { Wait(lock); ... dlclose() ... dlerror() ... }
bool IsLoaded() {...}
// ... access to symbols...
private:
static Lock lock;
}
Lock Lock::lock;
Run Code Online (Sandbox Code Playgroud)
这个类的用户(同时会有多个用户)希望使它成为这个类的静态成员,以避免为该类的每个对象多次加载共享库:
class NeedsALib {
public:
NeedsALib() { if (!myLib.IsLoaded()) { myLib.Load(); } }
private:
static LibLoader myLib;
}
LibLoader::myLib;
Run Code Online (Sandbox Code Playgroud)
这段代码的问题在于它可能会崩溃,因为它依赖于程序终止时破坏静态的顺序.如果锁在myLib之前消失了它会崩溃....
如何以安全的方式编写线程安全且不依赖于静态破坏的顺序?
不幸的是,我认为避免这种情况的唯一方法是使用不可移植的一次性初始化指令,并完全避免破坏锁。您需要处理两个基本问题:
这些约束的组合迫使您使用不可移植的机制来创建锁。
在 pthread 上,处理此问题的最直接方法是使用PTHREAD_MUTEX_INITIALIZER,它允许您静态初始化锁:
class LibLoader{
static pthread_mutex_t mutex;
// ...
};
// never destroyed
pthread_mutex_t LibLoader::mutex = PTHREAD_MUTEX_INITIALIZER;
Run Code Online (Sandbox Code Playgroud)
在 Windows 上,您可以使用同步一次性初始化。
或者,如果您可以保证在 main 运行之前只有一个线程,您可以使用单例模式而无需破坏,只需在 main() 之前强制触及锁即可:
class LibLoader {
class init_helper {
init_helper() { LibLoader::getLock(); }
};
static init_helper _ih;
static Lock *_theLock;
static Lock *getLock() {
if (!_theLock)
_theLock = new Lock();
return _theLock;
}
// ...
};
static init_helper LibLoader::_ih;
static Lock *LibLoader::_theLock;
Run Code Online (Sandbox Code Playgroud)
请注意,这使得可能不可移植(但很可能为真)的假设是,在所有非 POD 静态对象都被销毁之前,POD 类型的静态对象不会被销毁。据我所知,没有哪个平台不是这样的。