Some Rambles On Singleton Pattern

|

Singleton design pattern is a widely discussed topic among the blogspere, and there are many good articles dedicated to this massively applied design pattern, such as Implementing the Singleton Pattern in C# and The "Double-Checked Locking is Broken" Declaration. Just recently, I came across a relatively old blog article by Brad Abrams talking about how to make double checked locking Singleton pattern work properly in C#. With all those splendid reading as backbone, I add another two ways of implementing double checked locking pattern.

My first approach is mutated from the memory barrier trick Brad talked about in his blog article:

public sealed class Singleton
{
    private static Object syncRoot = new Object();
    private static Object instance;

    private Singleton() { }

    public static Singleton Instance
    {
        get
        {
            Singleton temp = null;
            if (instance == null)
            {
                lock (syncRoot)
                {
                    if (instance == null)
                    {
                        temp = new Singleton();

                        //Fully publish the Singleton object in memory to make it visible to all processors.
                        System.Threading.Thread.VolatileWrite(ref instance, temp);
                    }
                }
            }
            return temp;
        }
    }
}

Since Thread.VolatileWrite() method will do exactly what Thread.MemoryBarrier() does, so this approach is nothing different from Brad's.

Another approach to properly implement double checked locking is using TLS (Thread Local Storage) as The "Double-Checked Locking is Broken" Declaration article demonstrates. The original implementation is using Java, when implementing this approach in C#, you can get additional benefit out of ThreadStaticAttribute:

public sealed class Singleton
{
    [ThreadStatic]
    private static Int32 syncFlag = 0;
    private static Object syncRoot = new Object();
    private static Singleton instance;

    private Singleton() { }

    public static Singleton Instance
    {
        get
        {
            if (syncFlag == 0) // Is the current thread online?
            {
                lock (syncRoot)
                {
                    if (instance == null)
                    {
                        instance = new Singleton();
                    }
                }

                syncFlag = 1; // Indicate the current thread is online
            }
            return instance;
        }
    }
}  


Although, theoretically speaking, the two implementations shown above "should" work as expected, but without heavy testing on different hardware configurations, no one can make this guarantee:)

0 comments: