Plinq语句在静态构造函数中陷入僵局

Bor*_*itz 8 .net c# plinq task-parallel-library

我遇到了这种情况,其中静态构造函数中的以下plinq语句被死锁:

static void Main(string[] args)
{
    new Blah();
}

class Blah
{
     static Blah()
     {
         Enumerable.Range(1, 10000)
            .AsParallel()
            .Select(n => n * 3)
            .ToList();
     }
}
Run Code Online (Sandbox Code Playgroud)

它仅在构造函数是静态时发生.请有人向我解释一下.

是TPL错误吗?编译器?我?

Igo*_*sky 9

从静态构造函数调用线程代码通常很危险.为了确保静态构造函数只执行一次,CLR在锁定下执行静态构造函数.如果运行静态构造函数的线程在辅助线程上等待,则由于某种原因,辅助线程也可能需要CLR内部锁,并且程序将死锁.

这是一个更简单的代码示例,演示了这个问题:

using System.Threading;
class Blah
{
    static void Main() { /* Won’t run because the static constructor deadlocks. */ }

    static Blah()
    {
        Thread thread = new Thread(ThreadBody);
        thread.Start();
        thread.Join();
    }

    static void ThreadBody() { }
}
Run Code Online (Sandbox Code Playgroud)

第10.5.3.3节ECMA CLI规范的 "种族和死锁" 保证以下内容:

除非从类型初始化程序(直接或间接)调用的某些代码显式调用阻塞操作,否则单独的类型初始化不应创建死锁.

因此,只要静态构造函数中的操作没有阻塞线程,类型初始化器(即静态构造函数)就不会死锁.如果静态构造函数阻塞,则存在死锁的风险.