Everyone says static initializers are thread-safe, but I'm worried about a particular detail.
Let's say I have
static class MyStaticClass
{
public static readonly object myField = MyOtherClass.GetNewObject();
}
static class MyOtherClass
{
public static object GetNewObject()
{ /* arbitrary code that returns a new object */ }
}
Which of the following does C# guarantee, when MyStaticClass.myField
is not yet initialized?
If threads 1 and 2 try to access
myField
together (in that order),GetNewObject
will have started executing before thread 2 readsmyField
.If threads 1 and 2 try to access
myField
together (in that order),GetNewObject
will have finished executing before thread 2 readsmyField
.
How about the CLR in general: if its guarantees differ from C#'s, in what ways do they differ?
Has the behavior changed in more recent versions of the .NET framework?
Note:
It's a tricky question, and I think a complete answer would probably mention the difference between a static constructor and a static initializer, and how they interact with beforefieldinit
to produce the claimed result.
Case 2 will be honoured. A class field, property, or method cannot be dereferenced until the type has been initialized, and the type will not be initialized until the static constructor is completed. The static constructor is, to the best of my knowledge, therefore a blocking call.
http://msdn.microsoft.com/en-us/library/aa645612(v=vs.71).aspx
"The static constructor for a class executes at most once in a given application domain."
See this reply from Eric Lippert: https://stackoverflow.com/a/9399027/2420979 and note that "cctor" is IL for static constructor.
No.
Yes. The cctor will finish on one thread before the static method can be called on any thread.
The cctor is guaranteed to be called at most once, no matter how many threads are involved. If two threads call MyMethod "at the same time" then they race. One of them loses the race and blocks until the MyClass cctor completes on the winning thread.
Taken from MSDN:
If you second method is run in two different threads but never use the static class, it will never be built. However, if there is a reference to it, it will be initialized before any of the two thread access it.