I'll start off by saying that I'm already aware that in C++11 standard, static local initialization is now threadsafe. However, I am still required to maintain compatibility with Microsoft Visual C++ 6, so C++11 behavior isn't applicable.
I have a static library which uses a handful of static variables. I ran into issues with static variables getting used before they were initialized (single threaded):
class A
{
private:
static A Instance;
public:
static A& GetInstance() { return Instance; }
};
// And then from a different file:
A.GetInstance();
A.GetInstance() would return an uninitialized instance. So I followed this advice http://www.cs.technion.ac.il/users/yechiel/c++-faq/static-init-order-on-first-use-members.html and moved all my static variables into local methods.
class A
{
public:
static A& GetInstance()
{
static A Instance;
return Instance;
}
};
I thought that fixed the problem, but now I'm finding out that stuff isn't always getting initialized properly because I create other threads during startup.
Raymond Chen described the problem in 2004: https://blogs.msdn.microsoft.com/oldnewthing/20040308-00/?p=40363 , but nobody seemed to have any solutions. The only solutions anyone mentions are to use mutexes to prevent initialization from multiple threads. But this seems like a chicken and egg problem. Every type of mutex that I'm aware of requires some kind of initialization before it can be used. How can I make sure it gets initialized before I use it for the first time. I guess I'd have to make it static local. But how do I ensure it get initialized from one thread?
If I could ensure that I have one memory location initialized to a known value before anything else is initialized, I could use interlocked operations on it to spin wait to bootstrap my whole initialization. Is there any way to ensure one memory location is in a known state from multiple threads before any other initialization occurs? Or any kind of synchronization that can be done without the chicken and egg problem?
The usual solution to this problem is to use a static object that can be zero-initialized or constant-initialized combined with atomic operations to "bootstrap" yourself into a position where you can call more complex initialization safely.
Zero and constant initialization is guaranteed to happen before non-constant initialization and since it effectively happens simultaneously it doesn't rely on order of initialization.
A very simple example would use a zero-initialized pointer to the global static instance, that indicates if the static has been initialized, like so:
class A
{
private:
volatile static A* Instance; // zero-initialized to NULL
public:
static A& GetInstance() {
A* inst = Instance;
if (!inst) {
A* inst = new Instance(...);
A* cur = InterlockedCompareExchange(&Instance, newInst, 0);
if (cur) {
delete inst;
return *cur;
}
}
return *inst;
}
};
The downside of the above approach is that two (or more) one A
object might be created, if two (or more) threads both initially see A::Instance
as null. The code correctly selects only one A
object to be the true static global returned to all callers and the others are simply silently deleted, but this may be a problem when it isn't even possible to create more than one Instance
object in a process (e.g., because it backed by some fundamentally singleton resource, perhaps a handle to some hardware resource). There is also be some wasted work if more than one Instance
is created, which might matter if the creation process is expensive.
This pattern is sometimes called racy single-check.
A better solution that avoids the above pitfalls would be to use a mutex to guard the creation of the singleton. Of course, now mutex initialization has the same ordering problem, but we can use the above trick to fix that (and we know it's OK to create more than one mutex object).
class MutexHolder
{
private:
volatile static CRITICAL_SECTION* cs; // zero-initialized to NULL
public:
static CRITICAL_SECTION* get() {
A* inst = cs;
if (!inst) {
CRITICAL_SECTION* inst = new CRITICAL_SECTION();
InitializeCriticalSection(inst);
CRITICAL_SECTION* cur = InterlockedCompareExchange(&cs, newInst, 0);
if (cur) {
DeleteCriticalSection(inst);
delete inst;
return *cur;
}
}
return *inst;
}
};
class A
{
private:
static MutexHolder mutex;
static A* Instance; // zero-initialized to NULL
public:
static A& GetInstance() {
A* inst;
CRITICAL_SECTION *cs = mutex.get();
EnterCriticalSection(cs);
if (!(inst = Instance)) {
inst = Instance = new A(...);
}
EnterCriticalSection(cs);
return inst;
}
};
Here the MutexHolder
is a re-usable wrapper around the Windows CRITICAL_SECTION
object which performs lazy and thread-safe initialization inside the get()
method, and can be zero-initialized. This MutexHolder
is then used as a classic mutex to protect the creation of the static A
object inside A::GetInstance
.
You can make GetInstance
faster at the cost of some complexity with the use of double-checked locking: rather than getting the CRITICAL_SECTION
unconditionally, first check if Instance
is set (like the first example) and then return it directly if it is.
Finally, if you are targeting Windows Vista or later, Microsoft has added a ready-made tool which handles this directly: InitOnceExecuteOnce. You can find an worked example here. This is approximately analogous POSIX's to pthead_once
and works because initialization is performed using the constant INIT_ONCE_STATIC_INIT
.
In your case it would look something like:
INIT_ONCE g_InitOnce = INIT_ONCE_STATIC_INIT;
A* g_AInstance = 0;
BOOL CALLBACK MakeA(
PINIT_ONCE InitOnce,
PVOID Parameter,
PVOID *lpContext)
{
g_AInstance = new A(...);
return TRUE;
}
class A
{
private:
public:
static A& GetInstance() {
// Execute the initialization callback function
bStatus = InitOnceExecuteOnce(&g_InitOnce,
MakeA,
NULL,
NULL);
assert(bStatus);
return *g_AInstance;
}
};
Raymond Chen wrote a blog entry about this function which also makes for good reading.