所以我很高兴从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已完成,我认为这是不允许的.
这不是一个僵局,因为你没有做任何应该阻止的事情,也没有做任何应该破坏的事情.
你不使用任何资源A范围内B,反之亦然.因此,您的循环依赖是"安全的",因为没有任何东西会爆炸.
如果您跟踪打印输出显示的路径,则不应阻止任何内容:
Go(我怀疑)B(static构造函数),因为它未初始化.A.Initialize()A的static构造函数需要先执行B.Initialize()B 不需要初始化,但它没有处于完成状态(幸运的是没有设置变量,所以没有任何中断)A的static构造函数),然后返回A.Initialize()最终可以调用因为A已初始化B的static构造函数),然后返回Go你真正做的唯一事情就是存在一个不安全状态的可能性:访问一个构造函数没有完成执行的类.这是不安全的代码,虽然没有阻塞,但绝对代表了一个破碎的状态.
重要的一点是只涉及一个线程。引用博文:
然后静态构造函数启动一个新线程。当该线程启动时,CLR 发现即将在其静态构造函数“正在运行”的另一个线程的类型上调用静态方法。它会立即阻塞新线程,以便在主线程完成运行类构造函数之前,Initialize 方法不会启动。
在 Erics 的示例中,有两个线程相互等待。您只有一个线程,因此不会发生等待,因此:没有阻塞,也没有死锁。
| 归档时间: |
|
| 查看次数: |
198 次 |
| 最近记录: |