Task.Run 在静态初始化器中 [英] Task.Run in Static Initializer

查看:24
本文介绍了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.RunResult 会导致程序永久冻结.为什么?

Calling Task.Run and then Result in the static initializer causes the program to permanently freeze. Why?

推荐答案

您看到 CLR 的类初始化锁出现死锁.

You are seeing deadlock on the CLR's class initialization lock.

基本上,在类初始化之前,X 类中的任何内容都不能使用.但是你的匿名方法 () =>0 被编译为类的成员.在Task可以完成之前类的初始化不会完成,但是Task不能完成,因为它依赖于一个在初始化之前不允许运行的方法课程结束.

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 the Task can complete, but the Task can't complete because it depends on a method that isn't allowed to run until the initialization of the class is complete.

死锁.

您的示例显然是人为设计的,因此无法提供有关如何解决实际问题的建议.在这个特定的例子中,你可以用 Task.FromResult(0).Result; 替换初始化,但当然这更加人为;如果确实可用,您只需将 0 分配给该字段.

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 assign 0 to the field.

但是无论您的真实场景是什么,修复它的方法是不要创建类的初始化依赖于需要该类才能完成的某些外部组件的情况.例如,您可能会考虑使用 Lazy 来初始化值,或者直接调用该方法(这是允许的).

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).

无论一个例子是否人为设计,启动一个 Task 只是为了立即阻塞当前线程直到它完成都没有任何意义.因此,如果您有任何代码虽然字面上与此示例不完全相同,但仍然有效地执行相同的操作,那么显而易见的解决方法是将其更改为以串行、单线程方式执行.

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.

这篇关于Task.Run 在静态初始化器中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆