The new machine model of C++11 allows for multi-processor systems to work reliably, wrt. to reorganization of instructions.
As Meyers and Alexandrescu pointed out the “simple” Double-Checked Locking Pattern implementation is not safe in C++03
Singleton* Singleton::instance() {
if (pInstance == 0) { // 1st test
Lock lock;
if (pInstance == 0) { // 2nd test
pInstance = new Singleton;
}
}
return pInstance;
}
They showed in their article that no matter what you do as a programmer, in C++03 the compiler has too much freedom: It is allowed to reorder the instructions in a way that you can not be sure that you end up with only one instance of Singleton.
My question is now:
- Do the restrictions/definitions of the new C++11 machine model now constrain the sequence of instructions, that the above code would always work with a C++11 compiler?
- How does a safe C++11-Implementation of this Singleton pattern now looks like, when using the new library facilities (instead of the mock
Lockhere)?
If
pInstanceis a regular pointer, the code has a potential data race — operations on pointers (or any builtin type, for that matter) are not guaranteed to be atomic (EDIT: or well-ordered)If
pInstanceis anstd::atomic<Singleton*>andLockinternally uses anstd::mutexto achieve synchronization (for example, ifLockis actuallystd::lock_guard<std::mutex>), the code should be data race free.Note that you need both explicit locking and an atomic
pInstanceto achieve proper synchronization.