请考虑以下代码。
static class X
{
public static int Value = Task.Run(() => 0).Result;
}
class Program
{
static void Main(string[] args)
{
var value = X.Value;
}
}
在静态初始化程序中调用Task.Run
然后调用Result
会导致程序永久冻结。为什么呢?
答案 0 :(得分:14)
你在CLR的类初始化锁上看到了死锁。
基本上,在初始化类之前,类X
中的任何内容都不能使用。但是您的匿名方法() => 0
被编译为该类的成员。在Task
完成之前,类初始化不会完成,但Task
无法完成,因为它依赖于在类初始化完成之前不允许运行的方法。
死锁。
你的例子显然是做作的,所以不可能就如何解决你的现实问题提供建议。在这个特定的例子中,您可以用Task.FromResult(0).Result;
替换初始化,但当然这更加做作;如果它实际上可用,您只需将0
分配给该字段。
但无论您的实际情况如何,修复它的方法是不要创建一种情况,即类的初始化取决于需要该类才能完成的某些外部组件。例如,您可以考虑使用Lazy<T>
来初始化值,或者直接调用该方法(这是允许的)。
无论一个例子是否有人设定,启动Task
只会立即阻止当前线程直到它完成为止。因此,如果你有任何代码,虽然不完全像这个例子,但仍然有效地做同样的事情,显而易见的解决方法是将其更改为以串行,单线程方式执行。
答案 1 :(得分:0)
我认为问题的解释是不正确的。
基本上,在初始化类之前,不能使用类X中的任何内容。
但是任务无法完成,因为它取决于不是的方法 允许运行直到类的初始化完成。
如果是这样,在这种情况下,你应该得到一个编译器错误,但不会在运行时出现死锁。
无论如何,这段代码是合法的
static class X
{
public static int Value = Method();
private static int Method()
{
return 0;
}
}
Here是对问题的解释。