Note that there are some explanatory texts on larger screens.

plurals
  1. POPortable thread-safe lazy singleton
    text
    copied!<p>Greetings to all.</p> <p>I'm trying to write a thread safe lazy singleton for future use. Here's the best I could come up with. Can anyone spot any problems with it? The key assumption is that static initialization occurs in a single thread before dynamic initialisations. (this will be used for a commercial project and company is not using boost :(, life would be a breeze otherwise :)</p> <p>PS: Haven't check that this compiles yet, my apologies.</p> <pre><code>/* There are two difficulties when implementing the singleton pattern: Problem (a): The "global variable instantiation fiasco". TODO: URL This is due to the unspecified order in which global variables are initialised. Static class members are equivalent to a global variable in C++ during initialisation. Problem (b): Multi-threading. Care must be taken to ensure that the mutex initialisation is handled properly with respect to problem (a). */ /* Things achieved, maybe: *) Portable *) Lazy creation. *) Safe from unspecified order of global variable initialisation. *) Thread-safe. *) Mutex is properly initialise when invoked during global variable intialisation: *) Effectively lock free in instance(). */ /************************************************************************************ Platform dependent mutex implementation */ class Mutex { public: void lock(); void unlock(); }; /************************************************************************************ Threadsafe singleton */ class Singleton { public: // Interface static Singleton* Instance(); private: // Static helper functions static Mutex* getMutex(); private: // Static members static Singleton* _pInstance; static Mutex* _pMutex; private: // Instance members bool* _pInstanceCreated; // This is here to convince myself that the compiler is not re-ordering instructions. private: // Singletons can't be coppied explicit Singleton(); ~Singleton() { } }; /************************************************************************************ We can't use a static class member variable to initialised the mutex due to the unspecified order of initialisation of global variables. Calling this from */ Mutex* Singleton::getMutex() { static Mutex* pMutex = 0; // alternatively: static Mutex* pMutex = new Mutex(); if( !pMutex ) { pMutex = new Mutex(); // Constructor initialises the mutex: eg. pthread_mutex_init( ... ) } return pMutex; } /************************************************************************************ This static member variable ensures that we call Singleton::getMutex() at least once before the main entry point of the program so that the mutex is always initialised before any threads are created. */ Mutex* Singleton::_pMutex = Singleton::getMutex(); /************************************************************************************ Keep track of the singleton object for possible deletion. */ Singleton* Singleton::_pInstance = Singleton::Instance(); /************************************************************************************ Read the comments in Singleton::Instance(). */ Singleton::Singleton( bool* pInstanceCreated ) { fprintf( stderr, "Constructor\n" ); _pInstanceCreated = pInstanceCreated; } /************************************************************************************ Read the comments in Singleton::Instance(). */ void Singleton::setInstanceCreated() { _pInstanceCreated = true; } /************************************************************************************ Fingers crossed. */ Singleton* Singleton::Instance() { /* 'instance' is initialised to zero the first time control flows over it. So avoids the unspecified order of global variable initialisation problem. */ static Singleton* instance = 0; /* When we do: instance = new Singleton( instanceCreated ); the compiler can reorder instructions and any way it wants as long as the observed behaviour is consistent to that of a single threaded environment ( assuming that no thread-safe compiler flags are specified). The following is thus not threadsafe: if( !instance ) { lock(); if( !instance ) { instance = new Singleton( instanceCreated ); } lock(); } Instead we use: static bool instanceCreated = false; as the initialisation indicator. */ static bool instanceCreated = false; /* Double check pattern with a slight swist. */ if( !instanceCreated ) { getMutex()-&gt;lock(); if( !instanceCreated ) { /* The ctor keeps a persistent reference to 'instanceCreated'. In order to convince our-selves of the correct order of initialisation (I think this is quite unecessary */ instance = new Singleton( instanceCreated ); /* Set the reference to 'instanceCreated' to true. Note that since setInstanceCreated() actually uses the non-static member variable: '_pInstanceCreated', I can't see the compiler taking the liberty to call Singleton's ctor AFTER the following call. (I don't know much about compiler optimisation, but I doubt that it will break up the ctor into two functions and call one part of it before the following call and the other part after. */ instance-&gt;setInstanceCreated(); /* The double check pattern should now work. */ } getMutex()-&gt;unlock(); } return instance; } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload