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.
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 theInstance
property, will be locked until the type initializer has finished. Only after the field initializer has concluded, will threads be allowed to get theInstance
value. So no-one can seeInstance
beingnull
. – DecretalX
ends up being-1
even without threading. It is not a thread-safety issue. Instead, the initializerx = -1
runs first (it is on an earlier line in the code, a lower line number). Then the initializerX = GetX()
runs, which makes upper-caseX
equal to-1
. And then the "explicit" static constructor, the type initializerstatic C() { ... }
runs, which changes only lower-casex
. So after all that, theMain
method (orOther
method) can go on and read upper-caseX
. Its value will be-1
, even with just one thread. – Decretal