Thread-Safe Singleton Design Pattern in C#

Thread-Safe Singleton Design Pattern in C# with Examples

In this article, I am going to discuss How to Implement Thread-Safe Singleton Design Pattern in C# with Examples. Please read our previous article where we discussed Why do we need to create the Singleton Class as Sealed in C# with Examples. As of now, the way we have implemented the Singleton Design Pattern is not Thread Safe in a Multithread Environment. As part of this article, we are going to discuss the following pointers in detail.

  1. What is Thread-Safe in Singleton Design Pattern?
  2. What is Lazy Initialization in the Singleton Design Pattern?
  3. How to Implement the Singleton Design Pattern in a Thread-Safe Manner in C#?
  4. Implementation of Thread-Safe Singleton Design Pattern using Locks.
  5. Double-Check Locking Approach to Implement Thread-Safe Singleton Design Pattern in C#.
Example to Understand Thread-Safe in Singleton Design Pattern in C#.

Let’s understand How to Implement Thread-Safe Singleton Design Pattern in C# with Examples. Let us first see the problem that we face in a multithread environment if the Singleton Class is not Thread-Safe. So, create a class file with the name Singleton.cs and then copy and paste the following code into it. The following code example is self-explained, so please go through the comment lines for a better understanding. 

using System;
namespace SingletonDemo
{
    public sealed class Singleton
    {
        //This variable value will be increment by 1 each time the object of the class is created
        private static int Counter = 0;

        //This variable is going to store the Singleton Instance
        private static Singleton Instance = null;

        //The following Static Method is going to return the Singleton Instance
        public static Singleton GetInstance()
        {
            //This is not thread-safe
            if (Instance == null)
            {
                Instance = new Singleton();
            }

            //Return the Singleton Instance
            return Instance;
        }
        
        private Singleton()
        {
            //Each Time the Constructor is called, increment the Counter value by 1
            Counter++;
            Console.WriteLine("Counter Value " + Counter.ToString());
        }

        //The following method can be accessed from outside of the class by using the Singleton Instance
        public void PrintDetails(string message)
        {
            Console.WriteLine(message);
        }
    }
}

The way we have created the above Singleton Class, it is not Thread-Safe in a Multithreaded environment. That means, it is possible that two threads at the same time, check the if (instance == null) condition and it is also possible that both the threads found the condition as true and hence it will end up creating two instances of the Singleton Class.

Let’s modify the Main method of the Program class as follows to use multithread programming. As you can see in the below code, we are using Parallel.Invoke method and call PrintTeacherDetails and PrintStudentdetails methods parallelly. This will create two threads and invoke the two methods parallelly. Further, if you notice, in each method, we are calling the Static GetInstance() method of the Singleton class. That means now, two different threads, trying to call the same Static GetInstance() method of the Singleton class. Let us run the application and see the output and check how many times the constructor of the Singleton class is executed.

using System;
using System.Threading.Tasks;
namespace SingletonDemo
{
    class Program
    {
        //Example to Understand Thraed-Safe Problem with Singleton Design Pattern
        //When use in a Multithreaded Environment
        static void Main(string[] args)
        {
            //The following Code will Invoke both methods Parallely using two different Threads
            Parallel.Invoke(
                //Let us Assume PrintTeacherDetails method is Invoked by Thread-1
                () => PrintTeacherDetails(),
                //Let us Assume PrintStudentdetails method is Invoked by Thread-2
                () => PrintStudentdetails()
                );
            Console.ReadLine();
        }

        private static void PrintTeacherDetails()
        {
            //Thread-1 Calling the GetInstance() Method of the Singleton class
            Singleton fromTeacher = Singleton.GetInstance();
            fromTeacher.PrintDetails("From Teacher");
        }

        private static void PrintStudentdetails()
        {
            //At the same time, Thread-2 also Calling the GetInstance() Method of the Singleton Class
            Singleton fromStudent = Singleton.GetInstance();
            fromStudent.PrintDetails("From Student");
        }
    }
}

Here, within the main method, we use Parallel.Invoke method to invoke Multiple Methods parallelly, This concept is introduced in .NET Framework 4.0. If you are new to parallel programming then please read our Parallel Programming in C# with Real-Time examples article.

So in our example, we are using the Parallel.Invoke method to access the GetInstance Method parallelly. That means at the same time multiple threads are accessing the GetInstance Method. The above code is not Thread-Safe because the way we have written the code here two different threads can evaluate the condition if (instance == null) at the same time and both threads found it to be true and they both will create the instances, which violates the singleton design pattern. So, now run the application and it will give you the following output.

Example to Understand Thread-Safe Singleton Design Pattern in C#

The above output clearly shows that the counter value has incremented to 2, which proves that the constructor of the Singleton class is executed two times as a result two instances of the singleton class have been created in this case. So, if the Singleton class is not Thread-Safe, then we may end up creating multiple instances of the Singleton class in a Multithread Environment.

What is Lazy Initialization in Singleton Design Pattern in C#?

In our example, until and unless we invoke the GetInstance Method of the Singleton Class, the Singleton Instance is not going to be created. That means when we invoke the GetInstance Method of the Singleton class, then only the Singleton Instance is going to be created. This Delay of Singleton Instance creation is called Lazy Initialization in Singleton Design Pattern.

The Lazy Initialization i.e. the on-demand object creation of the Singleton Class works fine when we invoke the GetInstance Method in a Single-Threaded environment. But in a Multi-Threaded environment, it will not work as expected. In a Multi-Thread environment, the lazy initialization may end up creating multiple instances of the singleton class when multiple threads invoke the GetInstance Method parallelly at the same time which we just discussed. 

How to implement a Thread-Safe Singleton Design Pattern in C#?

There are many ways to Implement Thread-Safe Singleton Design Pattern in C#. They are as follows:

  1. Thread-Safety Singleton Implementation using Lock.
  2. Implementing Thread-Safety Singleton Design Pattern using Double-Check Locking.
  3. Using Eager Loading to Implement Thread-Safety Singleton Design Pattern
  4. Using Lazy<T> Generic Class to Implement Lazy Loading in Singleton Design Pattern.

We will discuss all the above mechanisms to Implement Thread-Safe Singleton Design Pattern in C#. In this article, we will discuss how to use Locks and Double-Check Locking Mechanisms to implement the Thread-Safe Singleton Design Pattern in C# which will create only one instance of the Singleton Class in a Multithread environment. The rest Two Mechanisms are going to be discussed in our next article.

Implementation of Thread-safe Singleton Design Pattern in C# using Locks.

Let us discuss how to implement the Thread-Safe Singleton Design Pattern in C# using locks. The point that you need to remember is Locks are the best option to handle the singleton instance in a multithread environment. Using locks we can synchronize the method. So that only one thread can access it at any given point in time. 

For a better understanding, please modify the Singleton Class as follows. In the following code, we lock the shared resource using the lock object and then check whether the instance is created or not. If the instance is already created then we simply return that instance else we will create the instance and then return that instance. The most important point that you need to remember is, as long as one thread locks the resource, no other thread can access the resource. The following example code is self-explained, so please go through the comment lines for a better understanding.

using System;
namespace SingletonDemo
{
    public sealed class Singleton
    {
        //This variable value will be increment by 1 each time the object of the class is created
        private static int Counter = 0;

        //This variable is going to store the Singleton Instance
        private static Singleton Instance = null;

        //To use the lock, we need to create one variable
        private static readonly object Instancelock = new object();

        //The following Static Method is going to return the Singleton Instance
        public static Singleton GetInstance()
        {
            //This is thread-safe
            //As long as one thread locks the resource, no other thread can access the resource
            //As long as one thread enters into the Critical Section, 
            //no other threads are allowed to enter the critical section
            lock (Instancelock)
            { //Critical Section Start
                if (Instance == null)
                {
                    Instance = new Singleton();
                }
            } //Critical Section End
            //Once the thread releases the lock, the other thread allows entering into the critical section
            //But only one thread is allowed to enter the critical section

            //Return the Singleton Instance
            return Instance;
        }
        
        private Singleton()
        {
            //Each Time the Constructor is called, increment the Counter value by 1
            Counter++;
            Console.WriteLine("Counter Value " + Counter.ToString());
        }

        //The following method can be accessed from outside of the class by using the Singleton Instance
        public void PrintDetails(string message)
        {
            Console.WriteLine(message);
        }
    }
}

With the above changes in place, now run the application and you will get the following output.

Implementation of Thread-safe Singleton Design Pattern in C# using Locks

The above code implementation using lock solves the Singleton Design Pattern Thread-Safe issues in a multithreading environment. But the problem is that it is slow down your application as only one thread can access the GetInstance method at any given point in time. We can overcome the above problem by using the Double-Checked Locking mechanism.

Double Checked Locking Approach to Implement Thread-Safe Singleton Design Pattern in C#.

In the Double-Checked Locking mechanism to implement Thread-Safe Singleton Design Pattern in C#, first, we will check whether the instance is created or not. If not then only we will synchronize the method using the lock. For a better understanding, please modify the Singleton class as follows. Here, you can see, we are checking the instance two times whether it is null or not. If it is not null, then we are returning the Singleton instance. If it is null, then we are using the lock to make sure only one thread can enter the critical section. And within the lock block, again we are checking the null condition to make sure only one instance of the Singleton Class is going to be created. The following example code is self-explained, so please go through the comment lines for a better understanding.

using System;
namespace SingletonDemo
{
    public sealed class Singleton
    {
        //This variable value will be increment by 1 each time the object of the class is created
        private static int Counter = 0;

        //This variable is going to store the Singleton Instance
        private static Singleton Instance = null;

        //To use the lock, we need to create one variable
        private static readonly object Instancelock = new object();

        //The following Static Method is going to return the Singleton Instance
        public static Singleton GetInstance()
        {
            //This is thread-Safe
            if (Instance == null)
            {
                //As long as one thread locks the resource, no other thread can access the resource
                //As long as one thread enters into the Critical Section, 
                //no other threads are allowed to enter the critical section
                lock (Instancelock)
                { //Critical Section Start
                    if (Instance == null)
                    {
                        Instance = new Singleton();
                    }
                } //Critical Section End
                //Once the thread releases the lock, the other thread allows entering into the critical section
                //But only one thread is allowed to enter the critical section
            }
            
            //Return the Singleton Instance
            return Instance;
        }
        
        private Singleton()
        {
            //Each Time the Constructor is called, increment the Counter value by 1
            Counter++;
            Console.WriteLine("Counter Value " + Counter.ToString());
        }

        //The following method can be accessed from outside of the class by using the Singleton Instance
        public void PrintDetails(string message)
        {
            Console.WriteLine(message);
        }
    }
}

With the above changes in place, now run the application and you will see the output as expected as shown in the below image.

Double Checked Locking Approach to Implement Thread-Safe Singleton Design Pattern in C#

In the next article, I am going to discuss the Lazy vs Eager Loading in Singleton Design Pattern in C# with Examples. Here, in this article, I try to explain How to Implement Thread-Safe Singleton Design Pattern in C# by using Lock and Double-Check Locking Mechanism in C# with Examples. I hope you enjoy this How to Implement Thread-Safe Singleton Design Pattern in C# with Examples article. Please give your feedback, questions, and suggestions about this article.

21 thoughts on “Thread-Safe Singleton Design Pattern in C#”

  1. This is way overkill!
    You don’t need to lock or the counter.

    This is the simplest thread-safe method: simply assign the value directly to the static variable.
    Thus:

    public sealed class Singleton
    {
    private static Singleton instance = new Singleton();
    private Singleton()
    {
    // initialisation code…
    }
    public static Singleton Instance
    {
    get
    {
    return instance;
    }
    }
    }

    “Since the CLR automatically calls a type’s class constructor the first time code attempts to access a member of the class, the first time a thread queries Singleton’s Instance (get) method, the CLR will automatically call the class constructor, which creates an instance of the object. Furthermore, the CLR ensures that calls to a class constructor are thread safe.”

    The only downside of this would be if your class has other static members that are accessed first, the instance would be created at that time, which might not be desirable. In this case, you could use your method, except you still don’t need to “count” or “lock”, you can simply use Interlocked.CompareExchange.
    Thus:

    static Singleton singleInstance;
    ///
    /// Get the one and only instance of this class.
    ///
    public static Singleton Instance
    {
    get
    {
    if (null == singleInstance)
    {
    Interlocked.CompareExchange(ref singleInstance, new Singleton(), null);
    }
    return singleInstance;
    }
    }

  2. Mohammad Mostafizur Rahman

    Is it necessary to put null checking just before the line “lock (Instancelock)” ?

  3. Here I need to 2 threads parallelly and that should have one instance
    I guess lock will block the thread if one is in progress

Leave a Reply

Your email address will not be published. Required fields are marked *