I need to write class that loads shared libraries. The dlopen() / dlerror() sequence needs a lock to be thread safe.
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;
The users of this class (there will be multiple at the same time) will want to make it a static member of this class to avoid loading a shared library multiple time for every object of the class:
class NeedsALib {
public:
NeedsALib() { if (!myLib.IsLoaded()) { myLib.Load(); } }
private:
static LibLoader myLib;
}
LibLoader::myLib;
The problem with this code is that it may / will crash, because it relies on the order of statics being destructed when the program terminates. If the lock is gone before myLib it will crash….
How can this be written in a safe manner that is thread safe and doesn’t rely on the order of static destruction ?
Unfortunately, I think the only way to avoid this is to both use unportable one-time initialization directives, and to avoid destroying the lock at all. There are two basic problems you need to deal with:
The combination of these constraints forces you to use a non-portable mechanism to create the lock.
On pthreads, the most straightforward way to handle this is with the
PTHREAD_MUTEX_INITIALIZER, which lets you statically initialize locks:On windows, you can use synchronous one-time initialization.
Alternately, if you can guarentee that there will only be one thread before main runs, you can use the singleton pattern without destruction, and just force the lock to be touched before main():
Note that this makes the possibly non-portable (but highly likely to be true) assumption that static objects of POD type are not destroyed until all non-POD static objects have been destroyed. I’m not aware of any platform in which this is not the case.