Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Double-Checked Locking Pattern in C++11?

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 Lock here)?
like image 412
towi Avatar asked May 15 '11 13:05

towi


2 Answers

If pInstance is 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 pInstance is an std::atomic<Singleton*> and Lock internally uses an std::mutex to achieve synchronization (for example, if Lock is actually std::lock_guard<std::mutex>), the code should be data race free.

Note that you need both explicit locking and an atomic pInstance to achieve proper synchronization.

like image 186
JohannesD Avatar answered Sep 23 '22 13:09

JohannesD


Since static variable initialization is now guaranteed to be threadsafe, the Meyer's singleton should be threadsafe.

Singleton* Singleton::instance() {
  static Singleton _instance;
  return &_instance;
}

Now you need to address the main problem: there is a Singleton in your code.

EDIT: based on my comment below: This implementation has a major drawback when compared to the others. What happens if the compiler doesn't support this feature? The compiler will spit out thread unsafe code without even issuing a warning. The other solutions with locks will not even compile if the compiler doesn't support the new interfaces. This might be a good reason not to rely on this feature, even for things other than singletons.

like image 38
Tim Seguine Avatar answered Sep 23 '22 13:09

Tim Seguine