What Is Double Checked Locking?

Double check locking is a technique to make singleton design thread safe. Look at below pseudo code, there are two checks. The first thread that will acquire the lock will construct the  Singleton object and pInstance is initialized. If other threads call instance method then due to first check initialization step is ignored. Due to second check race condition is prevented if multiple threads will try to initialize Singleton simultaneously.

Double checked locking and singleton design patternLet us implement this with actual c++ code on Linux . Then again we will discuss its reliability.

#include<iostream>
#include<pthread.h>
using namespace std;

class Singleton
{
public:
  static Singleton *GetInstance (void)
  {
    if (instance == 0)
      {
        // Critical segment.
	static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
	pthread_mutex_lock (&mutex);
	if (instance == 0)
	  {
	    instance = new Singleton;
	  }
	pthread_mutex_unlock (&mutex);
      }
    return instance;
  }
  void othermethod (void)
  {
    cout << “hello singleton \n"<<endl; 
  }; 

private: 
   Singleton () { }; 
   Singleton (Singleton const &); //need no implementation 
   void operator= (Singleton const &); // need no implementation
   static Singleton *instance; 
}; 

//initializing Singleton class static data member.
Singleton * Singleton::instance = 0;

int main () 
{ 
  // how to use 
  Singleton::GetInstance ()->othermethod ();
  return 0;
}

Note: The above code looks to be thread safe however the solution is not correct on all architecture. The compiler optimization for instruction reordering can cause side effects. The above code can be modified using memory barrier technique for more reliable.

Memory barrier

Memory barrier is an instruction for processor that guaranty order of instructions. All instructions before the barrier  must be completed and before the instruction after the barrier.

static Singleton *GetInstance (void)
  {
    if (instance == 0 && val == 0) { // val is bool flag
       // val is helper to check initialization
      static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
      pthread_mutex_lock(&mutex);
      if( instance == 0) {
      instance = new Singleton;
      }
      pthread_mutex_unlock(&mutex);
   }
    val = 1;
    return instance;
  }

Thread safe and c++ 11

According to c++ standard in section 6.7, static variables is always thread-safe. The following code ( from http://rosettacode.org/wiki/Singleton#Thread_safe_.28since_C.2B.2B11.29 ) is thread safe singleton design pattern.

class Singleton
{
     public:
         static Singleton &Instance()
         {
           // Since it's a static variable, if the class has
           //already been created,
            // It won't be created again.
           // And it **is** thread-safe in C++11.

            static Singleton myInstance;
           // Return a reference to our instance.
           return myInstance;
         }

        // delete copy and move constructors and assign operators
        Singleton(Singleton const&) = delete; // Copy construct
        Singleton(Singleton&) = delete; // Move construct
        Singleton& operator=(Singleton const&) = delete; // Copy assign
        Singleton& operator=(Singleton &&) = delete; // Move assign

       // Any other public methods

      protected:
          Singleton() {
          // Constructor code goes here.
          }

~Singleton()
{
// Destructor code goes here.
}

// And any other protected methods.
}

Reference:

http://www.cs.wustl.edu/~schmidt/PDF/DC-Locking.pdf



Related Contents to follow