Thursday, May 6, 2010

Singleton Pattern With C#

Singleton Pattern, the most widely known and applied pattern in software development circles. The pattern is put to use, whenever you need to share an instance between different contexts in an application. 


The pattern might not be new to most of you; as you might have heard or have experience in implementing for your own projects. Myself after working on this pattern for some time, thought of exploring more into this pattern to get an expert view from industry veterans. The finding were quite profound, as I came to know the language barriers that existed in implementing the Singleton pattern across different languages like C#, Java, and C++. Here I am going to concentrate mostly on C#, while at the same time skimming through some resources on implementing the pattern with C++ and Java.


So now lets get down to the real stuff. The Singleton pattern as everyone knows has different variants with myriad implementations. Here we are going to explore the three different variants of this pattern like Non-thread safe, Thread-safe, and Static Initialization.




Before starting to explore the these variants, lets see the basic guidelines to be followed when designing a Singleton pattern.
  • Make sure that, only single instance of a given class be created in a given AppDomain.
  • Single instance integrity must be guaranteed in a multi-threaded environment.
  • Provide a global point of access to the singleton class.
  • The Singleton class should be prevented from being subclassed. i.e; It must not be inheritable, for this the class should be supplied with the "sealed" keyword.
  • The Constructor should be set to Private and with zero parameters. If going to have parameterized version, you need to get a Factory pattern wrapped on top of this.
  • The member variable whose instance is to be made singleton, must be declared "private" and "static".
  • The method\procedure through which the instance is accessed, must be set to "public static".
  • The Singleton class should manage its own life-cycle including creation and releasing in unmanaged environments.
  • Never use Singleton pattern as a proxy object for maintaining global state in an Application; similar to a global variable.

Now lets start exploring all the different variants of Singleton Patterns, starting with the non-threaded variant aka the basic version.


Non-thread version
This being the basic versions among the available variants of singleton pattern, is seen being applied in academic projects and at times in commercial projects, where reasons could be either due to dead locks issues while using locks or due to nonavailability of locking features for the given language. The downside of using this approach is that, this could compromise on thread safety, which could lead to race conditions, affecting the application integrity and ultimately ending up with corrupted data. 
    Here is a sample code snippet implementing Singleton pattern the non-thread safe way.
    public sealed class Singleton
    {
        private static Singleton _instance = null;
    
        private Singleton()
        {
        }
    
        public static Singleton GetInstance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new Singleton();
                }
                return _instance;
            }
        }
    }
    I won't recommend the above non-threaded version for use in commercial projects, except for low profile desktop applications.


    Now lets move on to the next variant, the Thread safe one.


    Thread safe Version
    Lets see how to implement the Singleton class in a thread safe way using locks. 
    public sealed class Singleton
    {
        private static volatile Singleton _instance = null;
        private static Object _lock = new Object();
    
        private Singleton()
        {
        }
    
        public static Singleton GetInstance
        {
            get
            {
                if (_instance == null)
                {
                  lock(_lock)
                  {
                    if (_instance == null)
                      _instance = new Singleton();
                  }
                }
    
                return _instance;
            }
        }
    }
    Here you could find the some additions to the non-thread safe version. 


    First of all, a private member variable of object type "_lock" is declared exclusively for locking. By using a separate variable to lock on to, we could avoid dead lock scenarios being raised while accessing the "_instance" variable. 


    Next inside the "GetInstance" method, a lock is engaged before the instance is created so as to avoid multiple threads from executing the critical area where the instance is created. By placing locking code inside the null check condition, prevents locks from being engaged each time when "GetInstance()" is called, there by nullifying the performance overheads associated with locks. 

    Finally the volatile keyword is added to the singleton member variable. This guarantees that, the assignment to the instance variable is completed before the "_instance" variable is being accessed from any threads.

    The advantages of using this approach is that, the instance is created in only when the "GetInstance" method is called for the first time aka Lazy-Initialization, there by avoiding unnecessary instance creations when the application starts.


    Lets move on to the next version of Singleton Pattern the Static Initialization.


    Static Initialization
    I believe this is the most resource efficient way implementing a Singleton Pattern with C# applications, as this gives the advantage of lazy initialization along with freedom of avoiding locks.


    public sealed class Singleton
    {
        private static readonly Singleton _instance = new Singleton();
    
        private Singleton()
        {
        }
    
        public static Singleton GetInstance
        {
            get
            {
                return _instance;
            }
        }
    }


    Here in this version, the "_instance" variable is initialized only when the "GetInstance" member is called. The lock section is also removed from the "GetInstance" member, as now the instance is statically constructed while the class is called. Also the constructor is set to private like that of non-threaded version to restrict instantiation from other classes.
    Generally Static Initialization is not seen to be recommended by Design Patterns, as i came to know from other sources that; in languages like C++ and Java there was some ambiguity around the initialization order of static variables, which proposes a pattern called "Double-Check Locking" for implementing lazy loading in multi-threaded environments. The issue is caused whenever the call to the instance in our case "GetInstance" is first executed even before the constructor code, which is perfectly legal with the Java and C++ memory model, but will cause to break the solution.


    Practical Use
    Its always good to ask yourself this question like, What are the applications of Singleton pattern in a real world scenario. Here I am listing down a couple of application areas for potential use of Singleton pattern.


    Application Instrumentation - This is one area where Singleton pattern is put to use. Usually in applications lots of instrumentation code is being added for analysis and debugging purpose.


    Socket Programming - Here you could apply Singleton Patterns while dealing with ports.


    Hardware Resources - If you were to interface with hardware resource like Serial Port or external devices, its mandatory to have a single point of access to the device, through which the entire communication happen to pass on with.


    Device Spoolers - This is another scenario similar to Hardware Resources where the object should have exclusive access to the given device.


    The Otherside
    Its common to every man made objects in the world to leave room for improvement, so the same applies to this Singleton Pattern too. Here are some resources where you can find the issues and alternatives to this pattern.

    No comments: