静态初始化程序中的Task.Run

时间:2014-12-23 01:06:53

标签: c# .net task-parallel-library .net-4.5

请考虑以下代码。

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会导致程序永久冻结。为什么呢?

2 个答案:

答案 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是对问题的解释。