towi
towi

Reputation: 22347

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:

Upvotes: 11

Views: 1324

Answers (3)

Tim Seguine
Tim Seguine

Reputation: 2914

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.

Upvotes: 4

JohannesD
JohannesD

Reputation: 14471

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.

Upvotes: 5

David Heffernan
David Heffernan

Reputation: 613572

C++11 doesn't change the meaning of that implementation of double-checked locking. If you want to make double-checked locking work you need to erect suitable memory barriers/fences.

Upvotes: 1

Related Questions