考虑下面的代码。
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
会导致程序永久冻结。为什么?
考虑下面的代码。
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
会导致程序永久冻结。为什么?
你正在CLR的类初始化锁上看到死锁。
基本上,在类初始化完成之前,类X
中的任何内容都不能使用。但是你的匿名方法() => 0
被编译为该类的成员。类的初始化不会完成,直到Task
完成,但是Task
无法完成,因为它依赖于一个在初始化类完成之前不允许运行的方法。
死锁。
您的示例显然是人为的,因此无法提供如何修复您的实际问题的建议。在这个特定的示例中,可以将初始化替换为Task.FromResult(0).Result;
,但当然更加人为;如果那真的可用,你只需将0
分配给字段。
但是,无论您的实际场景如何,修复它的方式是不要创建一种情况,其中类的初始化取决于某些外部组件需要该类才能完成。例如,您可以考虑使用Lazy<T>
来初始化值,或者直接调用方法(这是允许的)。
无论一个示例是否人为,都没有必要启动一个Task
,然后立即阻塞当前线程,直到它完成。因此,如果您有任何代码,虽然不是字面上的例子,但实际上做的事情类似,显而易见的解决方法是将其更改为以串行单线程方式执行。
我认为问题的解释不正确。
基本上,在类X初始化之前,不能使用该类中的任何内容。
static class X
{
public static int Value = Method();
private static int Method()
{
return 0;
}
}
这里是问题的解释。