Think In Geek

In geek we trust

The Double Check Design Pattern

One of the deficiencies of actual programming languages, specially those ones still widely used that are old, such as C or C++, is that they were designed having in mind the sequential programming paradigm. This usually means that those languages don’t have standard ways to work with multithreading features, and you usually have to rely on third party libraries to develop thread safe software.

Today I’ll be discussing a design pattern called Double Check, which can be widely used to manage the resource access, elimination and initialization in a safe thread way.

Consider another common design pattern: the Singleton Pattern. A singleton is a special class which is allowed to have one and only one instance in a program. This pattern can be used in a variety of ways, one of the most usual one is to store global program information, which, as its name states, is global and unique to the application, so having more than one instance of that class would have the burden to mantain them synchronized, or even more nasty consequences.

There are different ways to implement a singleton class. I will focus on C#, but the example shown here could be easily extended to other languages such as C++ or Java. The trick on the pattern consists on declaring the class constructor private. This way we can be sure no one will be creating new instances of that class at will. After having done this, we have to provide a public method, which usually has the name getInstance, that will be the one actually creating this item and returning it to the caller.

The code would look similar to this one:

public sealed class Singleton
{
    private static Singleton instance = null;
 
    private Singleton(){}
 
    public static Singleton Instance
    {
        get
        {
            if (instance == null)
                instance = new Singleton();
            return instance;
        }
    }
}

Another way to create this singleton class would be doing the instantiation of the private variable on the class itself and not on the getInstance method, but this second way gives us a lazy initialization, so the variable is actually instantiated only when it’s needed, and never before (who knows, maybe we will never need it in some circumstances).

This implementation is perfect… as long as this method isn’t called twice (or more) at the same time. Consider what would happen if two threads requested an instance of the singleton class: both threads would check for the instance being null, and both threads would create the instance. That would sure lead to an unknown behaviour, and more than one instance of the class would be in the program, which is exactly what we wanted to avoid.

The first solution that comes in mind is to lock the method so multiple threads must wait to enter the method and get the singleton instance. It would look like this:

public sealed class Singleton
{
    private static Singleton instance = null;
    private static object sempahore = new Object();
 
    private Singleton(){}
 
    public static Singleton Instance
    {
        get
        {
            lock(semaphore);
            if (instance == null)
                instance = new Singleton();
            return instance;
        }
    }
}

This way we ensure that if n threads try to access the routine at the same time, only one will be initializing the singleton instance, since when the others gain the access to the method again, that instance won’t be null anymore. However, even if this solution is valid and works, it has a serious performance problem. Consider the situation where the instance has been already created. Then more than one thread access the routine again to get that instance. What will happen is that those threads will have to block and wait for other threads to finish, even if the instance is not null, so in any case will be created again. Conclusion: we are blocking threads that don’t need to be blocked. “Ok, you may say, we will put the lock inside the if clause, and we’ll have the issue resolved“. Let’s take a look at this solution:

public sealed class Singleton
{
    private static Singleton instance = null;
    private static object sempahore = new Object();
 
    private Singleton(){}
 
    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                lock(semaphore);
                instance = new Singleton();
            }
            return instance;
        }
    }
}

You don’t have to be a genious to see that this is not working, either. It will work after the instance has been created, because the threads won’t be entering the if clause, and they won’t be blocked. But if we are in the same situation as the described in the first place –this is, more than one thread entering the method before the instance has been created–, we have the same problem we had before: the singleton will be created more than once.

The final solution is simple: check again for the variable being null! This is why this pattern is called Double Check. The final code would look like this one:

public sealed class Singleton
{
    private static Singleton instance = null;
    private static object sempahore = new Object();
 
    private Singleton(){}
 
    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                lock(semaphore);
                if (instance == null)
                    instance = new Singleton();
            }
            return instance;
        }
    }
}

This way, we allow the threads to pass by the if clause if the instance has been already instantiated, and if it has not, the threads will get blocked, and the first one to gain access to the method will do the instantiation. Further threads will check again against the instance being null or not, so it won’t be created again.

Altough this pattern may be implemented similarly in other languages, be aware that, as I said before, a lot of them were never intended to deal with multithreading, and that compiler optimizations may give you code which is not really thread safe, or that actually is not optimized. Here you have a link discussing this issue with Java and C++: http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html.

Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn

, ,

Leave a Reply

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