在Static构造函数中调用时,使用Task.Run(...)包装方法会挂起

时间:2016-12-08 23:42:25

标签: c# task hang

我有一系列长时间运行的功能。我想将它们包装在Task中,以便我可以同时运行所有这些,而不是等待每一个顺序完成。

方法调用,静态类中存在所有相关的字段值和方法及属性。

我遇到一个问题,其中静态类构造函数无法完成,因为当我用Task.Run包装方法时它就会挂起。

符合必要的Mininmal, Complete and Verifiable示例要求......

using System;
using System.Linq;
using System.Threading.Tasks;

namespace MCVEAsyncHang
{
    class Program
    {
        private static readonly string[] _foo;

        static Program()
        {
            _foo = Task.WhenAll(Task.Run(new Func<string>(One))).Result;
        }

        private static string One()
        {
            return "Foo";
        }

        private static void Print()
        {
            Console.WriteLine(
                _foo.Aggregate((total, current) => 
                     total + string.Format("{0}{1}", Environment.NewLine, current)));
        }

        static void Main(string[] args)
        {
            Print();
            Console.WriteLine("Done");
            Console.ReadLine();
        }
    }
}

我知道我可以创建一些其他方法并调用它(如果必须的话,我会这样做),但如果可能的话,我宁愿将它保留在静态类构造函数中。

1 个答案:

答案 0 :(得分:8)

您的任务将在另一个线程中运行,需要调用if (xhr.readyState == XMLHttpRequest.DONE) { if (xhr.status == 200) { resolve(xhr.response); } else { reject(); } } 。该方法无法执行,直到您的_one类型已初始化为止。

任务的线程将看到Program类型已经已在主线程中初始化,因此将阻塞,直到该线程完成初始化类型。不幸的是,这不会发生 - 因为类型初始化程序将阻塞,直到您的任务完成。死锁。

基本上,你应该避免在静态构造函数中做太多工作。启动任务肯定感觉太多了。在这种情况下,死锁是显而易见的,但在其他情况下,它可能会更加微妙。 (在此之前我已经花了小时调试类型初始化程序循环,它真的,真的不好玩。那就是单一=线程代码 - 我不敢想它会有多痛苦在多线程环境中。)