DigestCPP

Lets Understand With Example

  • Home
  • Design Patterns
  • Adapter Design Pattern
  • Strategy Design Pattern
  • C++11 Features
  • std::thread c++11
  • Contact Us

Singleton Design Pattern

Definition: It Ensures a class has ONE instance and provide a global access to it.

Class Diagram:

Approach 1 (Using single if condition) for Singleton Design Pattern:

This approach is not safe for Multi-threaded program, We will face race condition and I will explain the problem in below example:

We have two thread 1 and thread 2.

SingletonLogger *SingletonLogger::GetInstance()
{
    if (m_pinstance == nullptr)
    {
        1. Thread 1 reached here and Context switching happened
           (OS scheduler give control to other thread (thread 2)
        2. Thread 2 also reached here, will create the object using new operator.
        3. Context switching happened again and thread 1 got CPU.
        4. Thread 1 will create the object using new operator.
        5. Now we have 2 objects and this is not expected from singleton class.

        m_pinstance = new SingletonLogger();
    }
        return m_pinstance;
}

Singleton Approach 2 (first lock then if condition):

This approach is safe for Multi-threaded program, but not optimised one. I will explain the problem in below example:

On every call(GetInstance()) we are acquiring the lock and checking the condition, assume we are calling 100 times then 100 times we are acquiring the lock and this is expensive operation so this approach is NOT optimised one.

SingletonLogger *SingletonLogger::GetInstance()
{
    std::lock_guard<std::mutex> lock(m_mutex);
    if (m_pinstance == nullptr)
    {
        m_pinstance = new SingletonLogger();
    }
        return m_pinstance;
}

Design PatternĀ Singleton Approach 3 (First if condition then lock):

This approach is not safe for Multi-threaded program, We will face race condition and I will explain the problem in below example:

We have two thread 1 and thread 2.

SingletonLogger *SingletonLogger::GetInstance()
{
    if (m_pinstance == nullptr)
    {
       1. Thread 1 reached here and Context switching happened
           (OS scheduler give control to other thread (thread 2)
        2. Thread 2 also reached and get the lock and will create the object.
        3. Context switching happened again and thread 1 got CPU.
        4. Thread 1 will get the lock and create the object using new operator.
        5. Now we have 2 objects and this is not expected from singleton class.
        

        std::lock_guard<std::mutex> lock(m_mutex);
        m_pinstance = new SingletonLogger();
    }
    return m_pinstance;
}

Approach 4 (First if condition then lock then if condition again):

This approach is safe for Multi-threaded program and its optimised one. I will explain the problem in below example:

After creation of first object, On every call(GetInstance()) we are checking the condition not acquiring the lock so this approach is optimised one.

SingletonLogger *SingletonLogger::GetInstance()
{
      if (m_pinstance == nullptr)
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        if (m_pinstance == nullptr)
        {
            m_pinstance = new SingletonLogger();
        }
    }
    return m_pinstance;
}

Click Here to See Code Example

Primary Sidebar

Copyright © 2021

  • Contact us