265

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; }
    }
}
urini
  • 32,483
  • 14
  • 40
  • 37
  • 1
    It is thread-safe. Suppose several threads want to get the property `Instance` at once. One of the threads will be told to first run the type initializer (also known as the static constructor). Meanwhile all other threads wanting to read the `Instance` property, will be ***locked*** until the type initializer has finished. Only after the field initializer has concluded, will threads be allowed to get the `Instance` value. So no-one can see `Instance` being `null`. – Jeppe Stig Nielsen Jul 07 '14 at 12:51
  • @JeppeStigNielsen The other threads are not locked. From my own experience I got nasty errors because of that. The guarantee is that only the fist thread will start the static initializer, or constructor, but then the other threads will try to use a static method, even if the construction process did not finish. – Narvalex Aug 20 '18 at 13:06
  • 2
    @Narvalex [This sample program](https://tio.run/##pZI/a8MwEMV3fYojZJCHCtN2aujkQpf0DzhQr4pyaQSKFKRzQzD@7K4tOzRxlpLcpvdOP@kdp8KdCqppyqDtN@SHQLidsdOTWGw8ylUrzBgLJEkrUEaGAJ@sYtDWIP44vYI3qS1PotybXXGLe@gx/IM26JNE5CQ98aRlHrsyZ4MzKL68Jpxri3w6qV4k4UJvUby7/ZOrIx8oomCJa@dx0jKuRlSZKOqbCHJN6I@E@mIeMe7FQP71Srx6Y9YzxnVhzxCjtPVoIzJWQbR25dK06mB2V501B9CWoIBneEUq@EAZejqrl0ez6vdG5AZxxx/SND0J4JFKb@Hx/u9DTfML) (source encoded in URL) cannot reproduce the problem you describe. Maybe it depends on what version of the CLR you have? – Jeppe Stig Nielsen Aug 20 '18 at 19:23
  • @JeppeStigNielsen Thanks for taking your time. Can you please explain to me why [here](https://tio.run/##pZJNb8IwDIbP7a@wqh1STVRF0y4gTp20y74kkMY1FDMilaRK3FKE@tu7NC0bHxcEudV2n9d@7dQMUpM2TWGE/IHpzhBuxv7xVzRba@RLGxj7viFOIoU048bAl7/3wb4@WCqxhHcuJAtduEu2j0ncQodhn7RGHYbRlLgmFlrmoSpR0qgMo28tCN@ERPYQ7F844UxsMPpQ25GqHR/IoWCBK6UxsIybEfskmtd3EfiKULcErxswmmaIORvGcdwGHbi@sMm5cOHTVeLu1zstOGHc5sEJ4s@Ebtr67FASeyherkVpGQcbhCSoYAKDYX8CXp9IrC2erfcu2wgqKHlW4AgCeISq9ddrGc/x@Nr6Gqya08uLRWbletV2DCWznetrbpmvSHPWT3TUchc@29vJ5p@6zR9yGqnQEqp/b5rmFw "C# (Visual C# Compiler) – Try It Online") the field is overriden? – Narvalex Aug 21 '18 at 12:57
  • 7
    @Narvalex With that code, upper-case `X` ends up being `-1` _even without threading_. It is not a thread-safety issue. Instead, the initializer `x = -1` runs first (it is on an earlier line in the code, a lower line number). Then the initializer `X = GetX()` runs, which makes upper-case `X` equal to `-1`. And then the "explicit" static constructor, the type initializer `static C() { ... }` runs, which changes only lower-case `x`. So after all that, the `Main` method (or `Other` method) can go on and read upper-case `X`. Its value will be `-1`, even with just one thread. – Jeppe Stig Nielsen Aug 21 '18 at 13:18

11 Answers11

201

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. https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors

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();
    }
}
Wollmich
  • 1,616
  • 1
  • 18
  • 46
Zooba
  • 11,221
  • 3
  • 37
  • 40
  • 56
    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 Jun 25 '09 at 13:16
  • 2
    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 Jun 30 '09 at 05:25
  • 26
    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 Aug 19 '10 at 17:23
  • 5
    For others who might be tripped up by this: Any static field members with initializers are initialized _before_ the static constructor is called. – Adam W. McKinley Dec 15 '11 at 16:25
  • Simple thread-safe singleton blank for everyday use: http://ilyatereschuk.blogspot.com/2013/12/c-simple-singleton-blank-for-everyday.html –  Dec 24 '13 at 06:53
  • @user2604650 There's nothing thread-safe about this, except for instanciating the singleton, which it would already be if it were initialized in the static constructor. Personally I think using a pattern like that for a singleton would be overkill, since in most cases the only time you access the singleton would be during the accessing of the static instance property, which in result is then the time of calling the static constructor. – Aidiakapi Jan 28 '14 at 16:55
  • 13
    The answer these days is to use `Lazy` - anyone who uses the code I originally posted is doing it wrong (and honestly it wasn't that good to begin with - 5-years-ago-me wasn't as good at this stuff as current-me is :) ). – Zooba Feb 04 '14 at 21:45
  • Why use a `Mutex` here? The `Acquire` method just returns a reference to an instance (this is a reference type). Whether the object referenced is mutable or immutable is irrelevant. The reference is to the same object no matter if the object mutates. Why do locking? Even if the instance was not "singleton" or "read-only", i.e. even if the field reference could change, since [reference assignments are atomic](http://stackoverflow.com/questions/5209623/), there would still be no need for locking/`Mutex`. I will downvote this answer @ +109 net upvotes... – Jeppe Stig Nielsen Jul 07 '14 at 14:57
  • @JeppeStigNielsen The idea is that you keep the mutex while you're using the object and then release it when you're done. Again, there are better ways to do it depending on how much overhead you want to force upon your users. I'm more a fan of an IDisposable/using() pattern now, but the concept is the same. – Zooba Jul 23 '14 at 16:59
  • 1
    @Zooba there's nothing to stop the caller from retaining the reference to Singleton after calling Release: `var s = Singleton.Acquire(); Singleton.Release(); s.Property = value;` – phoog Jun 08 '15 at 21:48
  • @phoog Yes, the bad guys can still win if they can run arbitrary code in your application. If you don't trust your fellow developers to write good code, you have problems that a singleton can't solve. – Zooba Jun 09 '15 at 22:58
  • 1
    @Zooba I don't trust myself to write good code, so I try to avoid requirements like "if you call this then you have to call that later" or "you can't use this after you call that." I'm not worried about bad guys, just human error. Sure, testing ought to catch it, but why rely on testing when you can almost always create a cleaner design that is less vulnerable to human error? – phoog Jun 09 '15 at 23:53
  • @phoog Fair point, but I'd throw "compiler enforced singletons" into the category of things that need a cleaner design. Making a more strictly enforced singleton doesn't help you when the problem is you shouldn't have a singleton. (Unsurprisingly, my views have changed in the 7 years since I wrote this answer, not that I ever considered it a really good idea :) ) – Zooba Jun 10 '15 at 21:01
  • @Zooba quite so. I didn't consider the wisdom (or lack thereof) of the overall design. – phoog Jun 10 '15 at 21:04
  • @AdamW.McKinley - note the order of static initialization is different between pre-.NET 4.0 and 4.0. http://codeblog.jonskeet.uk/2010/01/26/type-initialization-changes-in-net-4-0/ – Dave Black Feb 01 '16 at 22:51
  • @Zooba Can you make me more clear what does "run only once per application domain" stands for? What happens if I try to call this from my windows service application and also from the web Application? – OmGanesh Jan 30 '19 at 16:36
  • How does the static constructor synchronise to ensure it is only run once? Eg if I start a new thread and reference the class within the code from the new thread. Would the static initialiser run on that thread? Or would it run on the thread that created the object who created the thread? – rollsch Aug 10 '21 at 05:24
  • Where’s the call to `.Dispose()`? The code example detracts from the answer… – binki May 20 '22 at 17:07
93

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.
    }
}

EDIT:

Here is the demonstration:

static void Main(string[] args)
{
    var obj = new Foo<object>();
    var obj2 = new Foo<string>();
}

public class Foo<T>
{
    static Foo()
    {
         System.Diagnostics.Debug.WriteLine(String.Format("Hit {0}", typeof(T).ToString()));        
    }
}

In the console:

Hit System.Object
Hit System.String
Markus Safar
  • 6,324
  • 5
  • 28
  • 44
Brian Rudolph
  • 6,142
  • 2
  • 23
  • 19
  • typeof(MyObject) != typeof(MyObject); – Karim Agha Oct 28 '11 at 01:06
  • 6
    I think that is the point i'm trying to make. Generic types are compiled as individual types based upon which generic parameters are used, so the static constructor can and will be called multiple times. – Brian Rudolph Nov 03 '11 at 14:56
  • 1
    This is right when T is of value type, for reference type T only one generic type would be generated – sll Nov 28 '11 at 10:12
  • 3
    @sll: Not True... See my Edit – Brian Rudolph Dec 15 '11 at 15:59
  • See [Generics in the Runtime](http://msdn.microsoft.com/en-us/library/f4a6ta2h(v=vs.80).aspx) `When a generic type is first constructed with a value type as a parameter, the runtime creates a specialized generic type with the supplied parameter or parameters substituted in the appropriate places in the MSIL. Specialized generic types are created once for each unique value type used as a parameter` – sll Dec 15 '11 at 16:27
  • 2
    Interesting but really static cosntructor called for all types, just tried for multiple reference types – sll Dec 15 '11 at 16:31
  • @Brian Rudolph: what is shared is the _definition_ of the static constructor, take a look at [this code](http://ideone.com/vZC55g) – user1416420 Sep 14 '13 at 23:53
30

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

From the C# language specification:

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.

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
Derek Park
  • 45,824
  • 15
  • 58
  • 76
9

Here's the Cliffnotes version from the above MSDN page on c# singleton:

Use the following pattern, always, you can't go wrong:

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

   private Singleton(){}

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

Beyond the obvious singleton features, it gives you these two things for free (in respect to singleton in c++):

  1. lazy construction (or no construction if it was never called)
  2. synchronization
Jay Juch
  • 116
  • 1
  • 3
  • 4
    Lazy if the class is doesn't have any other unrelated statics (like consts). Otherwise accessing any static method or property will result instance creation. So I wouldn't call it lazy. – Schultz9999 Jun 11 '13 at 23:26
6

The static constructor will finish running before any thread is allowed to access the class.

    private class InitializerTest
    {
        static private int _x;
        static public string Status()
        {
            return "_x = " + _x;
        }
        static InitializerTest()
        {
            System.Diagnostics.Debug.WriteLine("InitializerTest() starting.");
            _x = 1;
            Thread.Sleep(3000);
            _x = 2;
            System.Diagnostics.Debug.WriteLine("InitializerTest() finished.");
        }
    }

    private void ClassInitializerInThread()
    {
        System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.GetHashCode() + ": ClassInitializerInThread() starting.");
        string status = InitializerTest.Status();
        System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.GetHashCode() + ": ClassInitializerInThread() status = " + status);
    }

    private void classInitializerButton_Click(object sender, EventArgs e)
    {
        new Thread(ClassInitializerInThread).Start();
        new Thread(ClassInitializerInThread).Start();
        new Thread(ClassInitializerInThread).Start();
    }

The code above produced the results below.

10: ClassInitializerInThread() starting.
11: ClassInitializerInThread() starting.
12: ClassInitializerInThread() starting.
InitializerTest() starting.
InitializerTest() finished.
11: ClassInitializerInThread() status = _x = 2
The thread 0x2650 has exited with code 0 (0x0).
10: ClassInitializerInThread() status = _x = 2
The thread 0x1f50 has exited with code 0 (0x0).
12: ClassInitializerInThread() status = _x = 2
The thread 0x73c has exited with code 0 (0x0).

Even though the static constructor took a long time to run, the other threads stopped and waited. All threads read the value of _x set at the bottom of the static constructor.

Trade-Ideas Philip
  • 1,067
  • 12
  • 21
  • So the static constructor blocks all other threads when it runs? That sounds like it cause introduce issues if you had a very slow static constructor and it ran late after the application had started (eg it would block the UI thread even if run from the threadpool). – rollsch Aug 10 '21 at 05:26
  • 1
    @rollsch My guess is that it would not block _all_ other threads, but rather, only threads that are currently attempting to access a member of the class whose static constructor is not yet finished. – hypehuman Feb 22 '23 at 06:56
6

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
  • 11,135
  • 4
  • 37
  • 34
  • 4
    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 Aug 10 '08 at 09:01
  • Derek, I'm familiar with the *beforefieldinit* "optimization" but, personally, I never worry about it. – Andrew Peters Aug 10 '08 at 09:28
  • working link for @DerekPark's comment: http://csharpindepth.com/Articles/General/Beforefieldinit.aspx. This link appears to be stale: http://www.ondotnet.com/pub/a/dotnet/2003/07/07/staticxtor.html – phoog Jun 08 '15 at 21:59
3

Although other answers are mostly correct, there is yet another caveat with static constructors.

As per section II.10.5.3.3 Races and deadlocks of the ECMA-335 Common Language Infrastructure

Type initialization alone shall not create a deadlock unless some code called from a type initializer (directly or indirectly) explicitly invokes blocking operations.

The following code results in a deadlock

using System.Threading;
class MyClass
{
    static void Main() { /* Won’t run... the static constructor deadlocks */  }

    static MyClass()
    {
        Thread thread = new Thread(arg => { });
        thread.Start();
        thread.Join();
    }
}

Original author is Igor Ostrovsky, see his post here.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
oleksii
  • 35,458
  • 16
  • 93
  • 163
3

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.

Community
  • 1
  • 1
Dominic Cooney
  • 6,317
  • 1
  • 26
  • 38
2

Just to be pedantic, 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.

Sam
  • 7,252
  • 16
  • 46
  • 65
Florian Doyon
  • 4,146
  • 1
  • 27
  • 37
1

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

Csa77
  • 649
  • 13
  • 19
Eran Kampf
  • 8,928
  • 8
  • 49
  • 47
0

The static constructor is locked. While the type initializer is running, any other thread which attempts to access the class in such a way that would trigger the type initializer will block.

However, the thread which is running the type initializer can access uninitialized static members. So be sure not to call Monitor.Enter() (lock(){}) or ManualResetEventSlim.Wait() from a type initializer if it is run from a UI thread—those are “interruptible” waits which result in the event loop running, executing arbitrary other parts of your program while your type initializer is still unfinished.

It is preferable for you to use managed blocking rather than unmanaged blocking. WaitHandle.WaitOne, WaitHandle.WaitAny, WaitHandle.WaitAll, Monitor.Enter, Monitor.TryEnter, Thread.Join, GC.WaitForPendingFinalizers, and so on are all responsive to Thread.Interrupt and to Thread.Abort. Also, if your thread is in a single-threaded apartment, all these managed blocking operations will correctly pump messages in your apartment while your thread is blocked:

binki
  • 7,754
  • 5
  • 64
  • 110