Singleton Pattern Part 2 | Design Pattern

In the last part we discussed about basic singleton pattern implementation in c++. In this part we are going to discuss its feasibility in multi threaded environment.

//C++ implementation
class  Singleton  {
public:
static  Singleton&  getInstance();

private:
Singleton();
Singleton(const  Singleton&);
Singleton&  operator=(const  Singleton&);  //  copyable
~Singleton();  //  indestructible static  Singleton*  instance_;
};

// implementation of getInstance() method
Singleton* Singleton::pInstance = 0;
Singleton* Singleton::getInstance()
{
    if (pInstance == 0) {
        pInstance = new Singleton;
    }
    return pInstance;
}

In single-threaded environment this generally works fine.
But in multi-thread environment this implementation is not safe.Lets see how
Suppose that we have two threads i.e Thread A and Thread B

  • Thread A enters Line 17 and determine that pInstance is NULL and no singleton object has yet been created. After determining it is then suspended.
  • Thread B enters Line 17 and determine that pInstance is NULL and then execute Line 18 and create a singleton object for pInstance. It then return pInstance to getInstance caller.
  • At some point Thread A resume and then enters through Line 18 and create another singleton for pInstance which clearly violates meaning of singleton as there are now two singleton object.

So , there are many ways to make it thread safe Lets Discuss them one by one.

1. Using Locking mechanism
In this method we just acquire a lock before testing pInstance NULL check.
Let see how:

// implementation of getInstance() method
Singleton* Singleton::pInstance = 0;
Singleton* Singleton::getInstance()
{
    Lock lock; //acquire Lock (actual syntax may differ)
    if (pInstance == 0) {
        pInstance = new Singleton;
    }
    Unlock lock; //release lock
    return pInstance;
}

Pros:

  • This method works perfectly in multi-thread environment.

Cons:

  • Very Expensive as access to the Singleton requires acquisition of a lock, but in reality we only require lock during initialization of pInstance i.e only the first time getInstance() is called.
  • If getInstance() is called n times, actual locking require is 1 but we are locking it n times so we are doing (n-1) unnecessary locks.

In the next post we will discuss how to reduce these unnecessary locks using Double Checked Locking Pattern DCLP.

Site Footer