views:

8292

answers:

11

In other words, is this Singleton implementation thread safe:

public class Singleton
{
    private static Singleton instance;

    private Singleton() { }

    static Singleton()
    {
        instance = new Singleton();
    }

    public static Singleton Instance
    {
        get { return instance; }
    }
}
A: 

The Common Language Infrastructure specification guarantees that "a type initializer shall run exactly once for any given type, unless explicitly called by user code." (Section 9.5.3.1.) So unless you have some whacky IL on the loose calling Singleton::.cctor directly (unlikely) your static constructor will run exactly once before the Singleton type is used, only one instance of Singleton will be created, and your Instance property is thread-safe.

Note that if Singleton's constructor accesses the Instance property (even indirectly) then the Instance property will be null. The best you can do is detect when this happens and throw an exception, by checking that instance is non-null in the property accessor. After your static constructor completes the Instance property will be non-null.

As Zoomba's answer points out you will need to make Singleton safe to access from multiple threads, or implement a locking mechanism around using the singleton instance.

Dominic Cooney
+32  A: 

Static constructors are guaranteed to be run only once per application domain, before any instances of a class are created or any static members are accessed. http://msdn.microsoft.com/en-us/library/aa645612.aspx

The implementation shown is thread safe for the initial construction, that is, no locking or null testing is required for constructing the Singleton object. However, this does not mean that any use of the instance will be synchronised. There are a variety of ways that this can be done; I've shown one below.

public class Singleton
{
    private static Singleton instance;
    // Added a static mutex for synchronising use of instance.
    private static System.Threading.Mutex mutex;
    private Singleton() { }
    static Singleton()
    {
        instance = new Singleton();
        mutex = new System.Threading.Mutex();
    }

    public static Singleton Acquire()
    {
        mutex.WaitOne();
        return instance;
    }

    // Each call to Acquire() requires a call to Release()
    public static void Release()
    {
        mutex.ReleaseMutex();
    }
}
Zooba
Note that if your singleton object is immutable, using a mutex or any synchronization mechanism is an overkill and should not be used.Also, I find the above sample implementation extremely brittle :-). All code using Singleton.Acquire() is expected to call Singleton.Release() when it's done using the singleton instance. Failing to do this (e.g. returning prematurely, leaving scope via exception, forgetting to call Release), next time this Singleton is accessed from a different thread it will deadlock in Singleton.Acquire().
Milan Gardian
Agreed, though I'd go further. If your singleton is immutable, using a singleton is overkill. Just define constants.Ultimately, using a singleton properly requires that the developers know what they are doing. As brittle as this implementation is, it is still better than the one in the question where those errors manifest randomly rather than as an obviously unreleased mutex.
Zooba
One way to lessen the brittleness of the Release() method is to use another class with IDisposable as a sync handler. When you acquire the singleton, you get the handler and can put the code requiring the singleton into a using block to handle the release.
CodexArcanum
+4  A: 

Using a static constructor actually is threadsafe. The static constructor is guaranteed to be executed only once.

From the C# language specification http://msdn.microsoft.com/en-us/library/aa645612(VS.71).aspx:

The static constructor for a class executes at most once in a given application domain. The execution of a static constructor is triggered by the first of the following events to occur within an application domain:

  • An instance of the class is created.
  • Any of the static members of the class are referenced.

So yes, you can trust that your singleton will be correctly instantiated.

Zooba made an excellent point (and 15 seconds before me, too!) that the static constructor will not guarantee thread-safe shared access to the singleton. That will need to be handled in another manner.

Derek Park
+2  A: 

Static constructors are guaranteed to fire only once per App Domain so your approach should be OK. However, it is functionally no different from the more concise, inline version:

private static readonly Singleton instance = new Singleton();

Thread safety is more of an issue when you are lazily initializing things.

Andrew Peters
+10  A: 

However, it is functionally no different from the more concise, inline version:

private static readonly Singleton instance = new Singleton();

Andrew, that is not fully equivalent. By not using a static constructor, some of the guarantees about when the initializer will be executed are lost. Please see these links for in-depth explanation:

Derek Park
+1  A: 

Andrew, that is not fully equivalent. By not using a static constructor, some of the guarantees about when the initializer will be executed are lost. Please see these links for in-depth explanation:

Derek, I'm familiar with the beforefieldinit "optimization" but, personally, I never worry about it.

Andrew Peters
+1  A: 

Static constructor is guaranteed to be thread safe. Also, check out the discussion on Singleton at DeveloperZen: http://www.developerzen.com/2007/07/15/whats-wrong-with-this-code-1-discussion/

Eran Kampf
+7  A: 

While all of these answers are giving the same general answer, there is one caveat.

Remember that all potential derivations of a generic class are compiled as individual types. So use caution when implementing static constructors for generic types.

class MyObject<T>
{
static MyObject() 
{
   //this code will get executed for each T.
}
}
Brian Rudolph
A: 

Just to be pendantic, but there is no such thing as a static constructor, but rather static type initializers, here's a small demo of cyclic static constructor dependency which illustrates this point.

Cheers!

Florian Doyon
A: 

Oh this is doing my head in! A few of these answers say in one breath that the static constructor is thread-safe, then in the next breath that it isn't! I don't understand. How can a static variable not be thread-safe?

Do you mean this?: Thread 1 requires the static property, it gets created and the constructor commences, before it finishes, thread 2 comes along and asks for the static property. Thread 2 thens gets an incorrect result because the static constructor has not yet finished its work.

Is this what you guys mean? Is this the only scenario in which the static property is not thread-safe? In other words, once the constructor has finished, can every thread expect to get exactly the same result from the static property?

Thanks

Rob