Singleton with Lock to prevent Racing and Deadlocks in C#


In some applications you will need to create a global instance of an object which can be used throughout the application. An example would be a global logging object which can log actions performed by the user.

When designing a solution for this problem you have to make sure that the resulting code is thread safe and also you have control on when the object is instantiated.

Below is the implementation of Singleton pattern which ensures that only one object of Singleton class is created, initialization is thread safe and initialization process is lazy.

    public sealed class Singleton
    {
        private static volatile Singleton instance;
        private static object staticObjLock = new Object();

        private Singleton() { }

        public static Singleton Instance
        {
            get
            {
                // Double-Check Locking.
                // Makes sure only one instance is created and also
                // instance initialization is thread safe.
                if (instance == null)
                {
                    lock (staticObjLock)
                    {
                        if (instance == null)
                            instance = new Singleton();
                    }
                }

                return instance;
            }
        }
    }

In the above code sample, the constructor of the class is made private so that no one can create an instance of the Singleton class.

When static property Instance is accessed first time the private static instance variable is initialized and from the second time onwards the same instance is returned to the caller. This approach makes sure that application is in control of when the instance is created.

To avoid concurrency issue when two threads try to initialize the object at the same time, the initialization code is wrapped in a lock statement. Lock statement locks on the private static object instead of current (this) object to avoid deadlock scenarios arising when the current object is locked by some other threads.

Private instance variable is declared volatile to make sure the variable is assigned before accessing it.

Checking for instance is null or not and locking the instance creation block solves the thread concurrency problems and also avoids lock on every call to the Instance property. This approach is called Double-Check Locking.