Is the C# static constructor thread safe?

2019-01-01 06:03发布

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

10条回答
深知你不懂我心
2楼-- · 2019-01-01 06:58

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
查看更多
不再属于我。
3楼-- · 2019-01-01 06:59

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.

查看更多
后来的你喜欢了谁
4楼-- · 2019-01-01 07:05

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.

查看更多
后来的你喜欢了谁
5楼-- · 2019-01-01 07:07

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/

查看更多
登录 后发表回答