Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create a thread-safe singleton pattern in Windows?

I've been reading about thread-safe singleton patterns here:

http://en.wikipedia.org/wiki/Singleton_pattern#C.2B.2B_.28using_pthreads.29

And it says at the bottom that the only safe way is to use pthread_once - which isn't available on Windows.

Is that the only way of guaranteeing thread safe initialisation?

I've read this thread on SO:

Thread safe lazy construction of a singleton in C++

And seems to hint at an atomic OS level swap and compare function, which I assume on Windows is:

http://msdn.microsoft.com/en-us/library/ms683568.aspx

Can this do what I want?

Edit: I would like lazy initialisation and for there to only ever be one instance of the class.

Someone on another site mentioned using a global inside a namespace (and he described a singleton as an anti-pattern) - how can it be an "anti-pattern"?

Accepted Answer:
I've accepted Josh's answer as I'm using Visual Studio 2008 - NB: For future readers, if you aren't using this compiler (or 2005) - Don't use the accepted answer!!

Edit: The code works fine except the return statement - I get an error: error C2440: 'return' : cannot convert from 'volatile Singleton *' to 'Singleton *'. Should I modify the return value to be volatile Singleton *?

Edit: Apparently const_cast<> will remove the volatile qualifier. Thanks again to Josh.

like image 640
Mark Ingram Avatar asked Oct 02 '08 20:10

Mark Ingram


People also ask

How do you create a thread-safe singleton?

Thread Safe Singleton in Java In general, we follow the below steps to create a singleton class: Create the private constructor to avoid any new object creation with new operator. Declare a private static instance of the same class. Provide a public static method that will return the singleton class instance variable.

Are singletons thread-safe?

Is singleton thread safe? A singleton class itself is not thread safe. Multiple threads can access the singleton same time and create multiple objects, violating the singleton concept. The singleton may also return a reference to a partially initialized object.

How do you create Singleton design pattern?

How to create Singleton design pattern? To create the singleton class, we need to have static member of class, private constructor and static factory method. Static member: It gets memory only once because of static, itcontains the instance of the Singleton class.


1 Answers

A simple way to guarantee cross-platform thread safe initialization of a singleton is to perform it explicitly (via a call to a static member function on the singleton) in the main thread of your application before your application starts any other threads (or at least any other threads that will access the singleton).

Ensuring thread safe access to the singleton is then achieved in the usual way with mutexes/critical sections.

Lazy initialization can also be achieved using a similar mechanism. The usual problem encountered with this is that the mutex required to provide thread-safety is often initialized in the singleton itself which just pushes the thread-safety issue to initialization of the mutex/critical section. One way to overcome this issue is to create and initialize a mutex/critical section in the main thread of your application then pass it to the singleton via a call to a static member function. The heavyweight initialization of the singleton can then occur in a thread-safe manner using this pre-initialized mutex/critical section. For example:

// A critical section guard - create on the stack to provide 
// automatic locking/unlocking even in the face of uncaught exceptions
class Guard {
    private:
        LPCRITICAL_SECTION CriticalSection;

    public:
        Guard(LPCRITICAL_SECTION CS) : CriticalSection(CS) {
            EnterCriticalSection(CriticalSection);
        }

        ~Guard() {
            LeaveCriticalSection(CriticalSection);
        }
};

// A thread-safe singleton
class Singleton {
    private:
        static Singleton* Instance;
        static CRITICAL_SECTION InitLock;
        CRITICIAL_SECTION InstanceLock;

        Singleton() {
            // Time consuming initialization here ...

            InitializeCriticalSection(&InstanceLock);
        }

        ~Singleton() {
            DeleteCriticalSection(&InstanceLock);
        }

    public:
        // Not thread-safe - to be called from the main application thread
        static void Create() {
            InitializeCriticalSection(&InitLock);
            Instance = NULL;
        }

        // Not thread-safe - to be called from the main application thread
        static void Destroy() {
            delete Instance;
            DeleteCriticalSection(&InitLock);
        }

        // Thread-safe lazy initializer
        static Singleton* GetInstance() {
            Guard(&InitLock);

            if (Instance == NULL) {
                Instance = new Singleton;
            }

            return Instance;
        }

        // Thread-safe operation
        void doThreadSafeOperation() {
            Guard(&InstanceLock);

            // Perform thread-safe operation
        }
};

However, there are good reasons to avoid the use of singletons altogether (and why they are sometimes referred to as an anti-pattern):

  • They are essentially glorified global variables
  • They can lead to high coupling between disparate parts of an application
  • They can make unit testing more complicated or impossible (due to the difficultly in swapping real singletons with fake implementations)

An alternative is to make use of a 'logical singleton' whereby you create and initialise a single instance of a class in the main thread and pass it to the objects which require it. This approach can become unwieldy where there are many objects which you want to create as singletons. In this case the disparate objects can be bundled into a single 'Context' object which is then passed around where necessary.

like image 138
8 revs Avatar answered Sep 21 '22 03:09

8 revs