Greg Beech's Website

Implementing the lazy initialize singleton pattern with generics

Generics are by far my favourite addition to .NET in version 2.0 - not least because I never have to write a strong typed collection again! But uses for them crop up all over the place. Recently I've been implementing a lot of classes with singleton instances, such as in configuration handlers, which use the initialize on first usage (lazy initialize) ideom and realized a generic class is the perfect place to encapsulate this.

The most common pattern for lazy-initialization is the double-check lock pattern. First it is checked whether the instance is null. If so, then a lock is taken on a synchronizing object and it is checked again whether the instance is null. The reason for the second check is that multiple threads could have simultaneously passed the first check, but only one can take the lock at a time and only the first thread to acquire it should create the instance. After passing the second check the instance is created.

In .NET 1.x it is slightly more complex than this as the memory model is weak and on a similarly weak architecture such as Intel's IA64 it is possible for the reference to be assigned (i.e. the instance appears non-null) before the object is constructed. This unconstructed but non-null instance would be visibile to threads running the initial check as they are not in the critical section at this point and as such the semantics of reads not moving before a lock acquire and writes not moving after a lock release do not apply. For this reason a temporary instance is created and then a memory barrier is used, which similarly to a lock release writes cannot cross, before the fully constructed temporary instance is assigned to the real singleton instance variable.

I believe this memory barrier technique may not be necessary in .NET 2.0 as the memory model has been strengthened, but am not a hundred percent sure and as such it stays in my preferred design pattern - in the worst case you'll lose a few milliseconds when the object is first constructed so it isn't going to be significant to the overall performance of an application.

The code listing is below as it's pretty short so didn't seem worth putting in a seperate download.

/// <summary>
/// Delegate to create an instance of a singleton.
/// </summary>
/// <typeparam name="T">
/// The type of object to create.
/// </typeparam>
/// <returns>
/// A new object of type <typeparamref name="T"/>.
/// </returns>
public delegate T SingletonCreator<T>();

/// <summary>
/// Encapsulates the lazy-initialize pattern for singleton objects by creating an 
/// instance of the specified type when the singleton value is first accessed. /// </summary> /// <typeparam name="T"> /// The type of singleton to create. /// </typeparam> public sealed class Singleton<T> { /// <summary> /// A synchronizing object for this instance of the singleton. /// </summary> private readonly object syncRoot = new object(); /// <summary> /// The delegate used to create the instance of the singleton. /// </summary> private readonly SingletonCreator<T> creator; /// <summary> /// The singleton instance of the object. /// </summary> private T instance; /// <summary> /// Creates a new singleton. /// </summary> /// <param name="creator"> /// The delegate used to create the singleton instance. /// </param> /// <exception cref="ArgumentNullException"> /// <paramref name="creator"/> is <strong>null</strong>. /// </exception> public Singleton(SingletonCreator<T> creator) { if (creator == null) { throw new ArgumentNullException("creator"); } this.creator = creator; } /// <summary> /// Gets the singleton instance of the object. /// </summary> /// <value> /// The singleton instance. /// </value> public T Instance { get { if (this.instance == null) { lock (this.syncRoot) { if (this.instance == null) { T temp = this.creator(); Thread.MemoryBarrier(); this.instance = temp; } } } return this.instance; } } }

You might be wondering why I declared a delegate to create the instance of the singleton rather than just specifying the new() constraint on the type - it is because this constraint requires the class to have a default public constructor and with singleton classes you want the constructors to be private or internal as otherwise anyone can create a new instance. Using another cool new feature of C# 2.0, anonymous delegates, it isn't much work to specify how to create the instance as shown below.

public class MyClass
{
    private static readonly Singleton<MyClass> singleton = new Singleton<MyClass>(
        new SingletonCreator<MyClass>(delegate { return new MyClass(); }));

    private MyClass()
    {
    }

    public static MyClass Instance
    {
        get
        {
            return singleton.Instance;
        }
    }
}

The down-sides of this approach are the slightly clunky syntax for declaring the singleton object, and that you potentially have two property accessors instead of one to get the singleton instance (although I would expect the outer one of these to be inlined by the JIT compiler so it should work out the same). The up-sides are that the syntax is quite a bit shorter and you can't make common mistakes such as forgetting about one of the null checks, which for me makes it a winner.


Posted May 03 2006, 08:04 PM by Greg Beech
Filed under: ,

Add a Comment

(required)  
(optional)
(required)  
Remember Me?

Enter the numbers above:
Copyright (C) Greg Beech. All rights reserved.
Powered by Community Server (Non-Commercial Edition), by Telligent Systems