Reputation: 17043
My code:
using System;
using System.Diagnostics;
using System.Threading.Tasks;
public class Program
{
private static void Main(string[] args)
{
var test = new Test(); // TypeInitializationException?
var test2 = new Test();
}
public class Test
{
public Test()
{
Trace.WriteLine("Test Created");
}
static Test()
{
Task.Factory.StartNew(
() =>
{
throw new Exception();
});
}
}
}
If I change the static const to :
static Test()
{
throw new Exception();
}
Then it is throwing TypeInitializationException! I thought static constructor is thread safe?
Is the C# static constructor thread safe?
private static void Main(string[] args)
{
Task.Factory.StartNew(
() =>
{
var test = new Test();
});
var test2 = new Test(); // HERE I GET THE EXCEPTION!!!!
}
public class Test
{
public Test()
{
Trace.WriteLine("Test Created");
}
static Test()
{
throw new Exception();
}
}
}
Upvotes: 0
Views: 510
Reputation: 203842
Thread safe is not a particularly helpful phrase to use. You should generally avoid using it as it doesn't really tell you what operations are and are not safe.
Instead it's important to specifically state what thread-related operations and situations are supported in any given context. One can then objectively and clearly state whether the expectations are violated.
C# will ensure that static constructors are run at some point before they are used, no matter how many threads might use the class, or whether another thread is currently running the static constructor.
C# will ensure that it doesn't run the static constructor more than once, no matter how many different threads might be using the same class at around the same time, or whether another thread uses a class while it is currently being initialized.
The specs specifically state that if a static constructor throws an exception in the one time that it runs then all future uses of that type will throw a TypeInitializationException
, which is what you are seeing.
The behavior that you are seeing is entirely in line with the behavior defined in the specifications.
Upvotes: 4
Reputation: 8860
Static constructor wraps all exceptions which are thrown inside into TypeInitializationException
and that doesn't have relation to thread safety.
It is guaranteed that constructor is executed once and only once, before first usage of a type (or no execution if type isn't used) not depending on how many threads access the type. This means it is thread safe.
Upvotes: 1
Reputation: 1064184
Thread-safe in this context only means that you don't need to worry about two threads invoking the static constructor at the same time, or one thread starting the static constructor, and a second thread thinking it has run and skipping the constructor, even though it hasn't finished (causing access to uninitialized fields).
If you throw an exception in the constructor, that is simply an error. Nothing to do with thread safety. Type initialization errors are very bad, and will keep happening until the static constructor can successfully complete.
Upvotes: 4