Is Meyers' Implementation of the Singleton Pattern Thread Safe

Is Meyers' implementation of the Singleton pattern thread safe?

In C++11, it is thread safe. According to the standard, §6.7 [stmt.dcl] p4:

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

GCC and VS support for the feature (Dynamic Initialization and Destruction with Concurrency, also known as Magic Statics on MSDN) is as follows:

  • Visual Studio: supported since Visual Studio 2015
  • GCC: supported since GCC 4.3

Thanks to @Mankarse and @olen_gam for their comments.


In C++03, this code wasn't thread safe. There is an article by Meyers called "C++ and the Perils of Double-Checked Locking" which discusses thread safe implementations of the pattern, and the conclusion is, more or less, that (in C++03) full locking around the instantiating method is basically the simplest way to ensure proper concurrency on all platforms, while most forms of double-checked locking pattern variants may suffer from race conditions on certain architectures, unless instructions are interleaved with strategically places memory barriers.

Leaky Meyers Singleton: is it threadsafe?

Yes, this is thread-safe: no two threads will ever try to initialize the same variable with static storage duration at the same time. That includes the entirety of evaluating the initializer.

How is Meyers' implementation of a Singleton actually a Singleton

This is a singleton because static storage duration for a function local means that only one instance of that local exists in the program.

Under the hood, this can very roughly be considered to be equivalent to the following C++98 (and might even be implemented vaguely like this by a compiler):

static bool __guard = false;
static char __storage[sizeof(Singleton)]; // also align it

Singleton& Instance() {
if (!__guard ) {
__guard = true;
new (__storage) Singleton();
}
return *reinterpret_cast<Singleton*>(__storage);
}

// called automatically when the process exits
void __destruct() {
if (__guard)
reinterpret_cast<Singleton*>(__storage)->~Singleton();
}

The thread safety bits make it get a bit more complicated, but it's essentially the same thing.

Looking at an actual implementation for C++11, there is a guard variable for each static (like the boolean above), which is also used for barriers and threads. Look at Clang's AMD64 output for:

Singleton& instance() {
static Singleton instance;
return instance;
}

The AMD64 assembly for instance from Ubuntu's Clang 3.0 on AMD64 at -O1 (courtesy of http://gcc.godbolt.org/ is:

instance():                           # @instance()
pushq %rbp
movq %rsp, %rbp
movb guard variable for instance()::instance(%rip), %al
testb %al, %al
jne .LBB0_3
movl guard variable for instance()::instance, %edi
callq __cxa_guard_acquire
testl %eax, %eax
je .LBB0_3
movl instance()::instance, %edi
callq Singleton::Singleton()
movl guard variable for instance()::instance, %edi
callq __cxa_guard_release
.LBB0_3:
movl instance()::instance, %eax
popq %rbp
ret

You can see that it references a global guard to see if initialization is required, uses __cxa_guard_acquire, tests the initialization again, and so on. Exactly in almost every way like version you posted from Wikipedia, except using AMD64 assembly and the symbols/layout specified in the Itanium ABI.

Note that if you run that test you should give Singleton a non-trivial constructor so it's not a POD, otherwise the optimizer will realize that there's no point to doing all that guard/locking work.

Is using new thread safe to instantiate a singleton in an implementation similar to Scott Meyer's singleton idiom?

Is using an instance pointer and new in that implementation still
guaranteed to be thread safe (a race condition could be a potential
reason for that error)?

Yes, it is thread safe.

From N4659:

9.7 Declaration statement [stmt.dcl]

Dynamic initialization of a block-scope variable with static storage
duration
(6.7.1) or thread storage duration (6.7.2) is performed the
first time control passes through its declaration; such a variable is
considered initialized upon the completion of its initialization
. If
the initialization exits by throwing an exception, the initialization
is not complete, so it will be tried again the next time control
enters the declaration. If control enters the declaration concurrently
while the variable is being initialized, the concurrent execution
shall wait for completion of the initialization.
If control
re-enters the declaration recursively while the variable is being
initialized, the behavior is undefined.

As myInstance is a block-scope variable with a static storage duration which is dynamically initialized, the code is thread-safe even if multiple threads are involved.

Make Meyers' Singleton thread safe and fast with lazy evaluation

So seems the answer to my question best expressed Fred Larson in his comment:

"Fast, thread-safe, lazy - pick any two."

Meyers Singleton thread safe with C++-98

The Meyer singleton isn't the best solution in general, and
especially not in a multithreaded environment. A more general
way of implementing a singleton would be:

class ClassA
{
static ClassA* ourInstance;
// ctor's, etc.
public:
static ClassA& instance();
};

and in the source file:

ClassA* ClassA::ourInstance = &instance();

// This can be in any source file.
ClassA&
ClassA::instance()
{
if ( ourInstance == NULL ) {
ourInstance = new ClassA;
}
return *ourInstance;
}

This is thread safe if no threads are created before entering
main (which should be the case), and it is not dynamically
loaded (which should also be the case—if the object is to
be unique, and accessible from the constructors of static
objects, then it has to be their when the static constructors
run). It also has the advantage of avoiding any order of
destruction problems.



Related Topics



Leave a reply



Submit