为什么在这种情况下没有死锁?

kmp*_*kmp 10 .net c#

所以我很高兴从Eric Lippert那里读到这篇文章然后,当然,他们的优秀评论和John Payson说:

一个更有趣的例子可能是使用两个静态类,因为这样的程序可能会死锁而没有任何可见的阻塞语句.

我想,是的,这很容易,所以我把它打倒了:

public static class A
{     
    static A()
    {
        Console.WriteLine("A.ctor");
        B.Initialize();
        Console.WriteLine("A.ctor.end");
    }

    public static void Initialize()
    {
        Console.WriteLine("A.Initialize");
    }
}
public static class B
{
    static B()
    {
        Console.WriteLine("B.ctor");
        A.Initialize();
        Console.WriteLine("B.ctor.end");
    }

    public static void Initialize()
    {
        Console.WriteLine("B.Initialize");
    }

    public static void Go()
    {
        Console.WriteLine("Go");
    }
}
Run Code Online (Sandbox Code Playgroud)

其输出(在调用之后B.Go())是:

B.ctor
A.ctor
B.Initialize
A.ctor.end
A.Initialize
B.ctor.end
Go
Run Code Online (Sandbox Code Playgroud)

没有僵局,我显然是一个失败者 - 所以为了使尴尬永久化,这是我的问题:为什么这里没有僵局?

这似乎是我的小的大脑,B.Initialize被称为的静态构造函数B已完成,我认为这是不允许的.

pic*_*ypg 6

这不是一个僵局,因为你没有做任何应该阻止的事情,也没有做任何应该破坏的事情.

你不使用任何资源A范围内B,反之亦然.因此,您的循环依赖是"安全的",因为没有任何东西会爆炸.

如果您跟踪打印输出显示的路径,则不应阻止任何内容:

  1. 打电话Go(我怀疑)
  2. 输入B(static构造函数),因为它未初始化.
  3. 打印
  4. 使用 A.Initialize()
  5. Astatic构造函数需要先执行
  6. 打印
  7. 使用 B.Initialize()
  8. B 不需要初始化,但它没有处于完成状态(幸运的是没有设置变量,所以没有任何中断)
  9. 打印出来,然后返回
  10. 打印出来(从Astatic构造函数),然后返回
  11. A.Initialize()最终可以调用因为A已初始化
  12. 打印出来,然后返回
  13. 打印出来(从Bstatic构造函数),然后返回
  14. Go

你真正做的唯一事情就是存在一个不安全状态的可能性:访问一个构造函数没有完成执行的类.这是不安全的代码,虽然没有阻塞,但绝对代表了一个破碎的状态.


Dan*_*rth 1

重要的一点是只涉及一个线程。引用博文:

然后静态构造函数启动一个新线程。当该线程启动时,CLR 发现即将在其静态构造函数“正在运行”的另一个线程的类型上调用静态方法。它会立即阻塞新线程,以便在主线程完成运行类构造函数之前,Initialize 方法不会启动。

在 Erics 的示例中,有两个线程相互等待。您只有一个线程,因此不会发生等待,因此:没有阻塞,也没有死锁。