Double-Checked Lock Singleton in C++11 Double-Checked Lock Singleton in C++11 multithreading multithreading

Double-Checked Lock Singleton in C++11


I think this a great question and John Calsbeek has the correct answer.

However, just to be clear a lazy singleton is best implemented using the classic Meyers singleton. It has garanteed correct semantics in C++11.

§ 6.7.4

... If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization. ...

The Meyer's singleton is preferred in that the compiler can aggressively optimize the concurrent code. The compiler would be more restricted if it had to preserve the semantics of a std::mutex. Furthermore, the Meyer's singleton is 2 lines and virtually impossible to get wrong.

Here is a classic example of a Meyer's singleton. Simple, elegant, and broken in c++03. But simple, elegant, and powerful in c++11.

class Foo{public:   static Foo& instance( void )   {      static Foo s_instance;      return s_instance;   }};


That implementation is not race-free. The atomic store of the singleton, while it uses release semantics, will only synchronize with the matching acquire operation—that is, the load operation that is already guarded by the mutex.

It's possible that the outer relaxed load would read a non-null pointer before the locking thread finished initializing the singleton.

The acquire that is guarded by the lock, on the other hand, is redundant. It will synchronize with any store with release semantics on another thread, but at that point (thanks to the mutex) the only thread that can possibly store is the current thread. That load doesn't even need to be atomic—no stores can happen from another thread.

See Anthony Williams' series on C++0x multithreading.


See also call_once. Where you'd previously use a singleton to do something, but not actually use the returned object for anything, call_once may be the better solution.For a regular singleton you could do call_once to set a (global?) variable and then return that variable...

Simplified for brevity:

template< class Function, class... Args>void call_once( std::once_flag& flag, Function&& f, Args&& args...);
  • Exactly one execution of exactly one of the functions, passed as f to the invocations in the group (same flag object), is performed.

  • No invocation in the group returns before the abovementioned execution of the selected function is completed successfully