Consider the following code.
static class X
{
public static int Value = Task.Run(() => 0).Result;
}
class Program
{
static void Main(string[] args)
{
var value = X.Value;
}
}
Calling Task.Run
and then Result
in the static initializer causes the program to permanently freeze. Why?
You are seeing deadlock on the CLR's class initialization lock.
Basically, nothing in the class
X
can be used until the class is initialized. But your anonymous method() => 0
is compiled to a member of the class. The class initialization won't complete until theTask
can complete, but theTask
can't complete because it depends on a method that isn't allowed to run until the initialization of the class is complete.Deadlock.
Your example is clearly contrived, so it's impossible to provide advice as to how to fix your real-world problem. In this particular example, you could replace the initialization with
Task.FromResult(0).Result;
but of course that's even more contrived; if that were actually usable, you'd just assign0
to the field.But whatever your real-world scenario is, the way to fix it is to not create a situation where initialization of the class depends on some external component needing that class for it to complete. You might consider, for example, using
Lazy<T>
to initialize the value, or to just call the method directly (which would be allowed).Whether an example is contrived or not, there's never any point in starting a
Task
only to immediately block the current thread until it completes. So if you have any code that, while not literally exactly like this example, still does effectively the same thing, the obvious fix is to change it to execute in a serial, single-threaded manner.I think the explanation of the problem isn't correct.
if so, at this case you should get a compiler error but not deadlock on runtime.
Anyway, this code is legal
Here is explanation of the problem.