【发布时间】:2018-09-07 21:03:53
【问题描述】:
这是标准中我感到困惑的部分:http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf#page=178&zoom=auto,87,610%22
2.1。如果类型尚未初始化,请尝试获取初始化锁。
2.2.1。如果不成功,查看该线程或等待该线程完成的任何线程是否已经持有锁。
2.2.2。如果是这样,则返回,因为阻塞会造成死锁。该线程现在将看到该类型的未完全初始化状态,但不会出现死锁。
下面的代码在我测试的时候死锁,好像和标准相矛盾:
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();
}
}
根据标准,我预计会发生以下情况:
- 主线程获取 Foo 的初始化锁。
- 主线程运行 Foo 的静态构造函数。
- 主线程创建 otherThread 并启动它。
- otherThread 开始等待一秒钟,从而确保第 5 点发生在第 6 点之前。
- 主线程开始等待 otherThread 完成。
- otherThread 尝试获取 Foo 的初始化锁,但由于主线程持有锁而失败。
- otherThread 放弃执行静态构造函数,因为主线程持有初始化锁并等待 otherThread。
- otherThread 运行 SomeFunction 并成功完成。
- 主线程返回。
这里有什么问题?
【问题讨论】:
-
请注意,规范的这一部分实际上是一个基本原理,它更像是评论而不是正式的保证或规则。它概述了提供实际保证的假设算法,但实现不需要实现这一点。实际的保证是“单独的类型初始化不应创建死锁除非从类型初始化程序(直接或间接)调用的某些代码显式调用阻塞操作。” (强调我的)。给定的示例通过在初始化程序中等待 (Join) 来明确违反此条件。
-
在我的 2013 年关于这个主题的文章的 cmets 中有一些关于这个问题的讨论:ericlippert.com/2013/01/31/the-no-lock-deadlock
标签: c# multithreading deadlock static-constructor