182

Is the following implementation, using lazy initialization, of Singleton (Meyers' Singleton) thread safe?

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

If not, why and how to make it thread safe?

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
Ankur
  • 11,239
  • 22
  • 63
  • 66
  • Can someone please explain why this is not thread safe. The articles mentioned in the links discuss thread safety using an alternative implementation (using a pointer variable i.e. static Singleton *pInstance). – Ankur Nov 02 '09 at 14:50
  • 1
    See: http://stackoverflow.com/questions/449436/singleton-instance-declared-as-static-variable-of-getinstance-method/449823#449823 – Martin York Nov 02 '09 at 19:37
  • See: http://stackoverflow.com/questions/1008019/c-singleton-design-pattern/1008289#1008289 – Martin York Nov 02 '09 at 19:43
  • Possible duplicate of [Singleton instance declared as static variable of GetInstance method](https://stackoverflow.com/questions/449436/singleton-instance-declared-as-static-variable-of-getinstance-method) – Trevor Boyd Smith Sep 04 '18 at 11:45

6 Answers6

205

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:

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.

Community
  • 1
  • 1
vgru
  • 49,838
  • 16
  • 120
  • 201
  • 3
    There is also an extensive discussion on the Singleton Pattern (lifetime and threadsafety) by Alexandrescu in Modern C++ Design. See Loki's site: http://loki-lib.sourceforge.net/index.php?n=Pattern.Singleton – Matthieu M. Nov 02 '09 at 14:57
  • 1
    You can create a thread-safe singleton with boost::call_once. – CashCow Jan 25 '12 at 15:03
  • 1
    Unfortunately, this part of the standard is not implemented in the Visual Studio 2012 C++ Compiler. Referred to as "Magic Statics" in the "C++11 Core Language Features: Concurrency" table here: http://msdn.microsoft.com/en-us/library/vstudio/hh567368.aspx – olen_garn Mar 27 '13 at 16:41
  • 1
    The snippet from the standard addresses construction but not destruction. Does the standard prevent the object from being destructed on one thread while (or before) another thread tries to access it at program termination? – stewbasic Jul 10 '17 at 00:50
  • IANA(C++ language)L but section 3.6.3 [basic.start.term] p2 suggests that it is possible to hit undefined behavior by trying to access the object after it has been destroyed? – stewbasic Jul 10 '17 at 00:58
  • Possible duplicate of [@MartinYork's answer](https://stackoverflow.com/a/449823/52074) to the [same question... but asked earlier](https://stackoverflow.com/q/449436/52074) – Trevor Boyd Smith Sep 04 '18 at 11:48
21

To answer your question about why it's not threadsafe, it's not because the first call to instance() must call the constructor for Singleton s. To be threadsafe this would have to occur in a critical section, and but there's no requirement in the standard that a critical section be taken (the standard to date is completely silent on threads). Compilers often implement this using a simple check and increment of a static boolean - but not in a critical section. Something like the following pseudocode:

static Singleton& instance()
{
    static bool initialized = false;
    static char s[sizeof( Singleton)];

    if (!initialized) {
        initialized = true;

        new( &s) Singleton(); // call placement new on s to construct it
    }

    return (*(reinterpret_cast<Singleton*>( &s)));
}

So here's a simple thread-safe Singleton (for Windows). It uses a simple class wrapper for the Windows CRITICAL_SECTION object so that we can have the compiler automatically initialize the CRITICAL_SECTION before main() is called. Ideally a true RAII critical section class would be used that can deal with exceptions that might occur when the critical section is held, but that's beyond the scope of this answer.

The fundamental operation is that when an instance of Singleton is requested, a lock is taken, the Singleton is created if it needs to be, then the lock is released and the Singleton reference returned.

#include <windows.h>

class CritSection : public CRITICAL_SECTION
{
public:
    CritSection() {
        InitializeCriticalSection( this);
    }

    ~CritSection() {
        DeleteCriticalSection( this);
    }

private:
    // disable copy and assignment of CritSection
    CritSection( CritSection const&);
    CritSection& operator=( CritSection const&);
};


class Singleton
{
public:
    static Singleton& instance();

private:
    // don't allow public construct/destruct
    Singleton();
    ~Singleton();
    // disable copy & assignment
    Singleton( Singleton const&);
    Singleton& operator=( Singleton const&);

    static CritSection instance_lock;
};

CritSection Singleton::instance_lock; // definition for Singleton's lock
                                      //  it's initialized before main() is called


Singleton::Singleton()
{
}


Singleton& Singleton::instance()
{
    // check to see if we need to create the Singleton
    EnterCriticalSection( &instance_lock);
    static Singleton s;
    LeaveCriticalSection( &instance_lock);

    return s;
}

Man - that's a lot of crap to "make a better global".

The main drawbacks to this implemention (if I didn't let some bugs slip through) is:

  • if new Singleton() throws, the lock won't be released. This can be fixed by using a true RAII lock object instead of the simple one I have here. This can also help make things portable if you use something like Boost to provide a platform independent wrapper for the lock.
  • this guarantees thread safety when the Singleton instance is requested after main() is called - if you call it before then (like in a static object's initialization) things might not work because the CRITICAL_SECTION might not be initialized.
  • a lock must be taken each time an instance is requested. As I said, this is a simple thread safe implementation. If you need a better one (or want to know why things like the double-check lock technique is flawed), see the papers linked to in Groo's answer.
Community
  • 1
  • 1
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • 2
    Uh oh. What happens if `new Singleton()` throws? – sbi Nov 02 '09 at 17:51
  • @Bob - to be fair, with a proper set of libraries, all the cruft having to do with non-copyability and a proper RAII lock would go away or be minimal. But I wanted the example to be reasonably self-contained. Even though singleton's are a lot of work for maybe minimal gain, I have found them useful in managing the use of globals. They tend to make it easier to find out where and when they're used a little better than just a naming convention. – Michael Burr Nov 02 '09 at 18:01
  • @sbi: in this example, if `new Singleton()` throws there's definitely a problem with the lock. A proper RAII lock class should be used, something like `lock_guard` from Boost. I wanted the example to be more or less self-contained, and it was already a bit of a monster so I left off exception safety (but called it out). Maybe I should fix that so this code doesn't get cut-n-pasted somewhere inappropriate. – Michael Burr Nov 02 '09 at 18:17
  • Why dynamically allocate the singleton? Why not just make 'pInstance' a static member of 'Singleton::instance()'? – Martin York Nov 02 '09 at 19:41
  • @Martin - done. You're right, that makes it a bit simpler - would be even better if I used an RAII lock class. – Michael Burr Nov 02 '09 at 22:45
  • Generally I use boost::call_once to create thread-safe singletons if there might be a race-condition. You can actually create a recurring template pattern to do all this which makes it easire to create singletons. (Heaven help us! That means there will be singletons all over the code!!!) The logic inside the call_once must not throw so your constructor must not do so. – CashCow Jan 25 '12 at 15:01
  • Where should `InitializeCriticalSection()` for `instance_lock` go? – user3819404 Apr 17 '19 at 04:29
10

Looking at the next standard (section 6.7.4), it explians how static local initialization is thread safe. So once that section of standard is widely implemented, Meyer's Singleton will be the preferred implementation.

I disagree with many answers already. Most compilers already implement static initialization this way. The one notable exception is Microsoft Visual Studio.

deft_code
  • 57,255
  • 29
  • 141
  • 224
6

The correct answer depends on your compiler. It can decide to make it threadsafe; it's not "naturallly" threadsafe.

MSalters
  • 173,980
  • 10
  • 155
  • 350
5

Is the following implementation [...] thread safe?

On most platforms, this is not thread-safe. (Append the usual disclaimer explaining that the C++ standard doesn't know about threads, so, legally, it doesn't say whether it is or not.)

If not, why [...]?

The reason it isn't is that nothing prevents more than one thread from simultaneously executing s' constructor.

how to make it thread safe?

"C++ and the Perils of Double-Checked Locking" by Scott Meyers and Andrei Alexandrescu is a pretty good treatise on the subject of thread-safe singletons.

sbi
  • 219,715
  • 46
  • 258
  • 445
2

As MSalters said: It depends on the C++ implementation you use. Check the documentation. As for the other question: "If not, why?" -- The C++ standard doesn't yet mention anything about threads. But the upcoming C++ version is aware of threads and it explicitly states that the initialization of static locals is thread-safe. If two threads call such a function, one thread will perform an initialization while the other will block & wait for it to finish.

sellibitze
  • 27,611
  • 3
  • 75
  • 95