Click here to Skip to main content
15,867,686 members
Articles / Programming Languages / C++

Singleton Pattern: Single Instance, but Multiple Implementations

Rate me:
Please Sign up or sign in to vote.
4.83/5 (10 votes)
27 Sep 2012CPOL5 min read 35.7K   286   23   7
A template based, thread safe singleton implementation in C++
In this article, I provide a template class that will be useful as it takes away the need for thread synchronization and reference counting.

Introduction

Singleton is a pattern which provides a design strategy which helps to control the instance creation of a class. It helps to maintain only a single instance (or variable instance numbers) of a class by making the constructor private and providing a instance creation function.

Singleton is a very widely used pattern. Well, at the same time, it can be implemented in different ways. The pattern specification says only a single instance or a controlled number of instances can be created. If we consider a C++ version of singleton, there are multiple ways in which we can implement the pattern. Another consideration is multithreading. We will consider the different design strategies and see how we can implement a thread safe singleton object.

The Simplest Design

See the below code snippet to implement a singleton:

C++
class XMLReader
{
public:
  XMLReader& GetInstance()
  {
      static XMLReader XMLReaderObj;
      return XMLReaderObj;
  }
private:
   XMLReader(){}
};

This is the simplest form of singleton implementation in C++. A static local object is created and its reference is returned. Since the static objects live in global memory, it will live till the process ends. Here, we cannot control the lifetime of the object. It gets destructed when the application main returns. Suppose we need to do some cleanup before the main returns. For example, we need to save some information to an XML file. We can use an XML library like MSXML for managing XML files. This library is COM based. We initialize COM using CoInitialize or CoInitializeEx once per thread and call CoUninitialize before the thread returns. See the full source code for XMLWriter below:

C++
class XMLWriter
{
public:
    static XMLWriter& GetInstance()
    {
        static XMLWriter SingletonObj;
        return SingletonObj;
    }
    bool UpdateXML(const DataHolder& DataHolderObj)
    {
       //XML updating code
    }
    ~XMLWriter()
    {
       _bstr_t bstrFileName(_T("E:\\Test.xml"));
       m_pXMLDom->save( bstrFileName );
    }
private:
    XMLWriter()
    {	
        InitDOM();
    }
    void InitDOM()
    {
        HRESULT hr = m_pXMLDom.CreateInstance(__uuidof(MSXML2::DOMDocument60));
        if (SUCCEEDED(hr))
        {
			m_pXMLDom->loadXML(       
			_bstr_t(_T("<?xml version='1.0'?>\n") 
			_T("<doc title='test'>\n")
			_T("   <page num='1'> \n") 
			_T("      <para title='Saved at last'> \n") 
			_T("          This XML data is finally saved.\n") 
			_T("      </para>\n")
			_T("   </page>\n")
			_T("   <page num='2'>\n") 
		        _T( "      <para>\n")
			_T("          This page is intentionally left blank.\n")
			_T("      </para>\n") 
			_T("   </page>\n")
			_T("</doc>\n")));
        }
    }
private:
    MSXML2::IXMLDOMDocumentPtr m_pXMLDom;
};

void main()
{
    //Initialize COM
    CoInitialize(0);
    XMLWriter& WriterObj = XMLWriter::GetInstance();
    ///some code using ReaderObj
    //...........
    CoUninitialize();
}

Certainly, this code will break the application and it will crash on exit. If we look at the destructor of XMLWriter, it is trying to save the loaded XML into a file. But before the main returns, we have uninitialized COM and the saving code needs COM environment. When the main returns, the destructor gets kicked and code to save file executes. Bang!!!

We can make the call to CoInitialize in the constructor and CoUninitialize in the destructor. But in a multi threaded application, we can’t guarantee in which thread's context the object is created and so CoInitialize is called. So, the CoInitialize may get called in one worker thread and CoUninitialize in the main thread (inside the destructor) as the application exits. In fact, the main thread has not called a matching CoInitialize. This can cause undefined results.

This is a simple example to show that we need control on the destruction process. When there is nothing to be done while the object is destroyed, it is OK to use the local static object. In fact, it is a threadsafe implementation. The compiler will do the necessary that a single instance of the static object is created when used in a multithreaded environment.

Now, we will look into other strategies in singleton implementation.

Creator and Destroyer Methods for Finer Control

See the below code snippet:

C++
class XMLReader
{
public:
    static XMLReader& CreateInstance()
    {
        if(!m_pXMLReader)
        {           
           m_pXMLReader = new XMLReader;
        }
        return (*m_pXMLReader);
    }
    static XMLReader& GetInstance()
    {
       return (*m_pXMLReader);
    }
    static void DestroyInstance()
    {
       delete m_pXMLReader;
    }
    ~XMLReader()
    {
    }
private:
   
    XMLReader()
    {
    }

private:
    static XMLReader* m_pXMLReader;
};

This code seems OK. But what happens if memory allocation failure happens in CreateInstance. It will be returning a NULL reference if new returns NULL. If the allocation failure is returned as std::bad_alloc, CreateInstance can throw an exception, which the singleton object creation code should be aware of. In the case of new returning NULL, GetInstance also returns a NULL reference, which can lead to a runtime error. A modified version of this implementation is shown below:

C++
class XMLReader
{
public:
    static XMLReader& CreateInstance()
    {
        try
        {
            if(!m_pXMLReader)
            {
                m_pXMLReader = new XMLReader;
            }
            return (*m_pXMLReader);
        }
        catch(std::bad_alloc& baException)
        {
            throw new ObjectCreationFailed(_T("Memory allocation failed"));
        }
        catch(...)
        {
            throw new ObjectCreationFailed(_T("Unknown reason"));
        }
    }
    static XMLReader& GetInstance()
    {
        if(!m_pXMLReader)
        {
            throw new ObjectDoesNotExist;
        }
        return (*m_pXMLReader);
    }
    static void DestroyInstance()
    {
        delete m_pXMLReader;
    }
    ~XMLReader()
    {
    }
private:
    XMLReader()
    {
    }
private:
    static XMLReader* m_pXMLReader;
};

The Multi Threading Aspects

In the above version, if any error occurs in the object creation, the object itself will not be created. This is a much better one. Now, what about thread safety aspects. What happens if CreateInstance is called simultaneously by two threads? Certainly, there is a possibility of multiple instances created. This violates the assumption of singleton of only a sole instance. How can we solve this?

The solution is very common in the multithreaded environment, we need to synchronize the object creation using a critical section or mutex. We shall discuss a complete solution in the coming sections.

The usage of the XMLReader class will be as shown below:

C++
XMLReader& XMLRdrObj =
XMLReader::CreateInstance();
//use XMLReader
XMLReader::DestroyInstance();

Suppose we have multiple child threads and both need the same singleton class. Probably, we need to call CreateInstance() from thread1 and 2 (say). Similarly, DestroyInstance before the threads end. But, how will we ensure that both threads see a valid instance always. What if thread1 ends first and thread2 continues to run? It will be catastrophic if thread1 invokes DestroyInstance and thread2 will be using an already deleted instance. This problem suggests that we need a reference counting mechanism, so that the object will be destroyed only when the final DestroyInstance is invoked. See the following implementation:

C++
class XMLReader
{
public:
    static XMLReader& CreateInstance()
    {
        try
        {
            if(!m_pXMLReader)
            {
                m_pXMLReader = new XMLReader;
            }
            ++m_nRefCount;
            return (*m_pXMLReader);
        }
        catch(std::bad_alloc& baException)
        {
            throw new ObjectCreationFailed(_T("Memory allocation failed"));
        }
        catch(...)
        {
            throw new ObjectCreationFailed(_T("Unknown reason"));
        }
    }
    static XMLReader& GetInstance()
    {
        if(!m_pXMLReader)
        {
            throw new ObjectDoesNotExist;
        }
        return (*m_pXMLReader);
    }
    static void DestroyInstance()
    {
        --m_nRefCount;
        if(0 == m_nRefCount)
            delete m_pXMLReader;
    }
    ~XMLReader()
    {
    }
private:
    XMLReader()
    {
    }
private:
    static int m_nRefCount;
    static XMLReader* m_pXMLReader;
};

This seems much better. We have one more pending issue to be solved, a thread safe instance creation. Here, I am introducing a complete solution which is a template class, that can be reused to make singleton classes.

The Solution

See the code below:

C++
/*/////////////////////////////////////////////////////////////////////////////////////
  SingletonTemplate.h - The SingletonTemplate is class which provides a generic template
  for implementing singleton pattern. This file contains the declaration/definition of the
  SingletonTemplate and its supporting classes.
 
  @written by :  Sudheesh.P.S
  @version    :  1.0            
  @date       :  26-09-2012
  @info       :  Initial version
//////////////////////////////////////////////////////////////////////////////////////*/
#pragma once

#include <exception>

/*/////////////////////////////////////////////////////////////////////////////////////
  CriticalSectionObject - A wrapper class for CRITICAL_SECTION. It manages the 
  initialization, locking, unlocking and deletion of CRITICAL_SECTION object. It is
  used by AutoCriticalSection class for automatic management of critical code areas.
//////////////////////////////////////////////////////////////////////////////////////*/
class CriticalSectionObject
{
public:
    CriticalSectionObject()
    {
        InitializeCriticalSection(&m_stCriticalSection);
    }
    void Lock()
    {
         EnterCriticalSection(&m_stCriticalSection);
    }
    void UnLock()
    {
         LeaveCriticalSection(&m_stCriticalSection);
    }
    ~CriticalSectionObject()
    {
        DeleteCriticalSection(&m_stCriticalSection);
    }
private:
    CRITICAL_SECTION m_stCriticalSection;
};

/*/////////////////////////////////////////////////////////////////////////////////////
  AutoCriticalSection - An automatic which uses the CriticalSectionSyncObj class to
  automatically lock the critical code area, by calling Lock in constructor and
  helps to leave the critical code by calling UnLock in destructor. Since it is done
  in constructor/destructor, it automatically happens.
/////////////////////////////////////////////////////////////////////////////////////*/

class AutoCriticalSection
{
public:
    AutoCriticalSection(CriticalSectionObject* pCSObj)
    {
        m_pCSObj = pCSObj;
        if( m_pCSObj  )
        {
            m_pCSObj->Lock();
        }
    }

    ~AutoCriticalSection()
    {
        if( m_pCSObj  )
        {
            m_pCSObj->UnLock();
        }
    }
private:
    CriticalSectionObject* m_pCSObj;
};

extern CriticalSectionObject g_CSObj;

/*/////////////////////////////////////////////////////////////////////////////////////
  GeneralException - A base class for exceptions
/////////////////////////////////////////////////////////////////////////////////////*/

class GeneralException
{
public:
	GeneralException(LPCTSTR lpctszDesciption)
	{
           m_ptcDescription = StrDup(lpctszDesciption);
	}
	~GeneralException()
	{
	   LocalFree(m_ptcDescription);
	}
	TCHAR* GetDescription()
	{
	   return m_ptcDescription;
	}
private:
	TCHAR* m_ptcDescription;
};

/*/////////////////////////////////////////////////////////////////////////////////////
  ObjectCreationFailedException - It is thrown when the object creation fails. This
  can be due to memory allocation failure or any other unknown cases.
/////////////////////////////////////////////////////////////////////////////////////*/

class ObjectCreationFailedException:public GeneralException
{
public:
    ObjectCreationFailedException(LPCTSTR lpctszDesciption):GeneralException(lpctszDesciption)
    {
    }
};

/*/////////////////////////////////////////////////////////////////////////////////////
  ObjectCreationFailedException - Thrown when a NULL object exist. This is a precaution
  when GetInstance is called on a destroyed instance (after DestroyInstance).
/////////////////////////////////////////////////////////////////////////////////////*/

class ObjectDoesNotExistException:public GeneralException
{
public:
    ObjectDoesNotExistException():GeneralException(_T("Object does not exist"))
    {
    }
};

/*///////////////////////////////////////////////////////////////////////////////////////
  SingletonTemplate - Singleton is a pattern which provides a design strategy which
  helps to control the instance creation of a class. It helps to maintain only a single
  instance of a class by making the constructor private and providing a CreateInstance
  function to create the class instance. The SingletonTemplate class provides a template
  class which can simplify the implementation of singleton classes. It synchronizes the
  instance creation with a critical section and also counts the reference for each 
  CreateInstance and decrements the reference for each DestroyInstance. 
  The requirements for using this class are:
  (1) - Make the constructors of target singleton class private
  (2) - Add the SingletonTemplate as friend of the target class (please sample class)
///////////////////////////////////////////////////////////////////////////////////////*/

template <class T> class SingletonTemplate 
{
public:
    /*////////////////////////////////////////////////////////////////////////////////
      Creates the instance of the singleton class. It is thread safe and keeps
      the reference count.
    ////////////////////////////////////////////////////////////////////////////////*/
    static T& CreateInstance()
    {
        try
        {
            AutoCriticalSection ACSObj(&g_CSObj);
            if( 0 == m_pTSingleInstance )
            {
                m_pTSingleInstance = new T;
            }
            ++m_nRefCount;
        }
        catch(std::bad_alloc)
        {
            throw new ObjectCreationFailedException(_T("Memory allocation failed"));
        }
        catch(...)
        {
            throw new ObjectCreationFailedException(_T("Unknown reason"));
        }
        return *m_pTSingleInstance;
    }

    /*///////////////////////////////////////////////////////////////////////////////////
      Returns the instance of the singleton class. If not exists, creates a new instance
    ///////////////////////////////////////////////////////////////////////////////////*/
    static T& GetInstance()
    {
        if( 0 == m_pTSingleInstance )
        {            
            throw new ObjectDoesNotExistException;
        }
        return *m_pTSingleInstance;
    }

    /*//////////////////////////////////////////////////////////////////////////////////
      Destroys the instance of the singleton class. It is thread safe and decrements
      the reference count. If the reference count is zero deletes the instance.
    /////////////////////////////////////////////////////////////////////////////////*/
    static void DestroyInstance()
    {
        AutoCriticalSection ACSObj(&g_CSObj);
        (m_nRefCount > 0) ? --m_nRefCount:m_nRefCount;
        if( 0 == m_nRefCount )
        {
            delete m_pTSingleInstance;
            m_pTSingleInstance = 0;
        }
    }
private:
    static T* m_pTSingleInstance;
    static int m_nRefCount;
};

template <class T> T* SingletonTemplate<T>::m_pTSingleInstance = 0;
template <class T> int SingletonTemplate<T>::m_nRefCount = 0;

The following code shows how to use SingletonTemplate class:

C++
#pragma once

#include "SingletonTemplate.h"

class SequenceGenSingleton 
{
    friend class SingletonTemplate<SequenceGenSingleton>;
public:
    ~SequenceGenSingleton(void);
    long GetNextSeqNum();
private:
    SequenceGenSingleton(void);
    SequenceGenSingleton(int nInitVal);
private:
    long m_lSeqNum;    
};

The following code shows the usage of this class:

C++
SingletonTemplate<SequenceGenSingleton>::CreateInstance();
SequenceGenSingleton& SingleObj = SingletonTemplate<SequenceGenSingleton>::GetInstance();
SingleObj.GetNextSeqNum();
SingletonTemplate<SequenceGenSingleton>::DestroyInstance();

The SingletonTemplate should be made the friend of the target singleton class (this gives access to the private constructor).

DLLs and Singleton

In the case of usage from a DLL, the code can be as shown below:

C++
BOOL WINAPI DllMain( IN HINSTANCE hDllHandle, 
         IN DWORD     dwReason, 
         IN LPVOID    lpvReserved )
 {
   switch ( dwReason )
   {
    case DLL_PROCESS_ATTACH:
	 SingletonTemplate<SequenceGenSingleton>::CreateInstance();
      break;

    case DLL_PROCESS_DETACH:
         SingletonTemplate<SequenceGenSingleton>::DestroyInstance();
      break;
   }
}

Usage from a Thread

In the case of usage from a child thread, the code can be as shown below:

C++
DWORD WINAPI MyWorkerThread(LPVOID)
{
    SingletonTemplate<SequenceGenSingleton>::CreateInstance();
    //…………..
    //The thread code
    //…………..
    SingletonTemplate<SequenceGenSingleton>::DestroyInstance();
    return 0;
}

The thread function can have multiple return paths. So we need to call DestroyInstance in all return paths. This gives the possibility to define an automatic class that can automate the release process. It can be as shown below:

C++
/*///////////////////////////////////////////////////////////////////////////////////////
  AutoSingleton - Makes the calls to CreateInstance and DestroyInstance automatic.
  This makes the usage of SingletonTemplate easy in the case of multiple return paths.
///////////////////////////////////////////////////////////////////////////////////////*/

template <class T> class AutoSingleton
{
public:
	AutoSingleton()
	{
    	   SingletonTemplate<T>::CreateInstance();
	}
	~AutoSingleton()
	{
	   SingletonTemplate<T>::DestroyInstance();
	}
};

AutoSingleton<SequenceGenSingleton> AutoSingletonObj;
SequenceGenSingleton& SingleObj = SingletonTemplate<SequenceGenSingleton>::GetInstance();

The wrapup

This is all that I have to offer now. I hope the template class provided will be useful as it takes away the need for thread synchronization and reference counting. We can make a singleton class which is thread safe just by parametrizing the SingletonTemplate with the required class and making it a friend of your class.

History

  • 26th September, 2012: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
India India
A senior engineer who likes reading and coding Smile | :) . I can be reached at sudheeshps@gmail.com

Comments and Discussions

 
QuestionAndrei Alexandrescu: Modern C++ Design Pin
Dmitriy Iassenev3-Oct-12 7:08
Dmitriy Iassenev3-Oct-12 7:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.