c# - C# 中的静态构造函数死锁是否与 ECMA CLI 标准相矛盾?

标签 c# multithreading deadlock static-constructor

这是我感到困惑的标准部分:http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf#page=178&zoom=auto,87,610%22

2.1. If the type is not yet initialized, try to take an initialization lock.

2.2.1. If not successful, see whether this thread or any thread waiting for this thread to complete already holds the lock.

2.2.2. If so, return since blocking would create a deadlock. This thread will now see an incompletely initialized state for the type, but no deadlock will arise.

以下代码在我测试时出现死锁,这似乎与标准相矛盾:

public static class Foo {
    static Foo() {
        var otherThread = new Thread(() => { Thread.Sleep(1000); SomeFunction(); });
        otherThread.Start();
        otherThread.Join();
    }
    public static void SomeFunction() {
    }
}
class Program {
    static void Main() {
        Foo.SomeFunction();
    }
}

根据标准,我预计会发生以下情况:

  1. 主线程获取 Foo 的初始化锁。
  2. 主线程运行 Foo 的静态构造函数。
  3. 主线程创建 otherThread 并启动它。
  4. otherThread 开始等待一秒,从而确保第 5 点发生在第 6 点之前。
  5. 主线程开始等待 otherThread 完成。
  6. otherThread 尝试获取 Foo 上的初始化锁,但由于主线程持有该锁而失败。
  7. otherThread 放弃执行静态构造函数,因为主线程持有初始化锁并等待 otherThread。
  8. otherThread 运行 SomeFunction 并成功完成。
  9. 主线程返回。

这里出了什么问题?

最佳答案

“等待此线程完成的任何线程”是指使用静态线程的初始化锁进行等待的任何线程,而不是使用任何可能的同步机制进行等待的线程。静态初始化机制无法知道其他线程正在另一个线程上使用某种完全不同的机制等待。

引用的部分指的是以下示例不会死锁的事实:

public class A
{
    static A()
    {
        Thread.Sleep(TimeSpan.FromSeconds(1));
        B.DoNothing();
    }
    public static void DoNothing() { }
}
public class B
{
    static B()
    {
        Thread.Sleep(TimeSpan.FromSeconds(1));
        A.DoNothing();
    }
    public static void DoNothing() { }
}
private static void Main()
{
    Task.Run(() => B.DoNothing());
    A.DoNothing();
}

这个示例不会死锁,因为一个线程正在等待另一个线程释放静态初始化程序锁,因此当该线程最终请求原始线程拥有的静态初始化程序锁时,引用的子句就会启动,它只是跳过锁。

关于c# - C# 中的静态构造函数死锁是否与 ECMA CLI 标准相矛盾?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52229614/

相关文章:

c# - ASP.NET WebApi - 如何获得 "allow"而不是 "require"客户端证书?

c# - 初始化实例变量

c# - 客户端未从服务器多线程接收数据

java - 如何在多线程环境中使构建器模式线程安全?

Java:ExecutorService线程与CountDownLatch同步导致死锁?

sql-server-2008 - SQL Server 存储过程行号问题

C# 如何在命令行应用程序中接收系统关闭或退出事件

c# - 在 C# 中复制数组的任何更快的方法?

java - JAVA中的多处理

java - Mysql select ...更新死锁