Writing a thread safe singleton has its difficulties. One of them is making sure that the dynamic creation of the inner singleton object is thread safe, while locking as few mutexes as possible.

Let’s first look at a naive Instance static member function:

MyClass* MyClass::Instance() 
{ 
    if (!pInstance) { 
        pInstance = new .... 
    }
    return pInstance; 
}

Obviously, it is not thread safe. Two threads can cause the instance to be created twice. A natural solution is just to use a mutex:

MyClass* MyClass::Instance() 
{ 
    // Mutex is freed when the local lock object is destructed
    mutex lock("Mutex0");
    
    if (!pInstance) { 
        pInstance = new .... 
    }
    return pInstance; 
}

Assuming that MyClass::Instance() is called very frequently, the last implementation will slow down the execution, since locking (especially a mutex) can be very very slow. However, locking is only needed for the instance’s creation, and not for every time we are trying to get the instance. Following is a very simple improvement:

MyClass* MyClass::Instance() 
{ 
    if (!pInstance) {
        mutex lock("Mutex0");
    
        if (!pInstance) { 
            pInstance = new .... 
        }
    }
    return pInstance; 
}

Every caller who enters the function after pInstance was allocated will not lock the mutex. Callers who enter the function before the instance was created are still synchronized with the mutex.

References

Posted by Ofer Kapota | | [7] comments

7 Comments »

  1. There are issues with this:
    http://en.wikipedia.org/wiki/Double-checked_locking

    Specifically, compilers may optimize the pInstance in such a way that pInstance will point to a partially constructed object.

    Comment by EJ — November 21, 2007 @ 3:13 am

  2. A simple alternative is to use a function such as pthread_once on POSIX or the InitOnce methods in Vista which will run a method a single time regardless of how many threads call it.

    As EJ notes above, double checked locking will fail on some compilers even if volatile is used. You need to lock for all access to the pointer.

    Comment by Scottt — August 27, 2008 @ 4:37 am

  3. Not positively sure about C++, but Java allows something really simpler:

    public class MyClass
    {
    private final static instance = new MyClass();

    public static MyClass getInstance()
    {
    return instance;
    }
    }

    This ensures the static field is initialized only once. An alternative, if startup code is more complex, is to used a static constructor :

    public class MyClass
    {
    private final static instance;

    static {
    // some global initialization stuff…
    instance = new MyClass();
    }

    public static MyClass getInstance()
    {
    return instance;
    }
    }

    This is not to start a C++/Java war ; I’ve made more Java than C++, and want to learn ;)

    Comment by Al — October 6, 2008 @ 9:50 am

  4. That is one of the things that led to the revisions in the Java memory model a few years ago. The new C++ standard has the notion to address this sort of thing.

    Here’s what a quick google search turns up on the problem (in C++)

    http://www.devarticles.com/c/a/Cplusplus/C-plus-in-Theory-Why-the-Double-Check-Lock-Pattern-Isnt-100-ThreadSafe/

    http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

    Comment by Bill Robertson — October 10, 2008 @ 12:01 am

  5. As someone mentioned earlier, this becomes problematic as you’re running into the anti-pattern of double checked locking. This idiom has been tried again and again, only to realize that it does not work.

    I know you can get around it by using ‘volatile’ in Java and possibly the same thing in C++.

    Comment by Mahmoud Abdelkader — October 10, 2008 @ 5:02 pm

  6. double check idiom is virtually not implementable in C, since C has no memory model. It can be implemented on different architectures by different means. C Volatile doesn’t have java semantics (aka explicit memory fence), so it cannot be relied upon.

    imo, the best x-platform to implement double check locking is via thread local storage (similar but not necessary the same to java’s ThreadLocal) and mutex. Check the thread local storage (next to free and no memory fence (important!)), if null grab the mutex and do the standard initialization.

    Comment by stanimir — December 21, 2008 @ 11:16 pm

  7. ahh yes, sry for the double-post wikipedia is dead wrong on it.

    Comment by stanimir — December 21, 2008 @ 11:17 pm

RSS feed for comments on this post. TrackBack URI

Leave a comment