Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread-safety of static initializers in C#

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?

  1. If threads 1 and 2 try to access myField together (in that order), GetNewObject will have started executing before thread 2 reads myField.

  2. If threads 1 and 2 try to access myField together (in that order), GetNewObject will have finished executing before thread 2 reads myField.

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.

like image 572
user541686 Avatar asked Jun 26 '13 21:06

user541686


People also ask

Is static thread-safe C?

No, static functions are not inherently thread-safe. Even your simple example isn't. Assuming both intvariable and stringvariable are supposed to be updated at the same time, another thread could observe the state of c1 between the two assignments, leading to data corruption.

Are static global variables thread-safe?

Static variables are not thread safe. Instance variables do not require thread synchronization unless shared among threads. But, static variables are always shared by all the threads in the process. Hence, access to static variable is not thread safe.

What is static initialization in C?

When static keyword is used, variable or data members or functions can not be modified again. It is allocated for the lifetime of program. Static functions can be called directly by using class name. Static variables are initialized only once. Compiler persist the variable till the end of the program.


2 Answers

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 cctors call MyMethod, directly or indirectly! Now is it ever possible for a static method like MyMethod to be called before the cctor of MyClass completes?

No.

Is that still true even if there are multiple threads involved?

Yes. The cctor will finish on one thread before the static method can be called on any thread.

Can the cctor be called more than once? Suppose two threads both cause the cctor to be run.

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.

like image 121
Haney Avatar answered Sep 28 '22 08:09

Haney


Taken from MSDN:

Static members are initialized before the static member is accessed for the first time and before the static constructor, if there is one, is called.

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.

like image 43
Simon Belanger Avatar answered Sep 28 '22 07:09

Simon Belanger