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