2013-02-01 142 views
10

所以我高高兴兴地从埃里克利珀阅读this,然后,当然,优秀的意见,并在他们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"); 
    } 
} 

其输出(呼叫B.Go()后):

B.ctor 
A.ctor 
B.Initialize 
A.ctor.end 
A.Initialize 
B.ctor.end 
Go 

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

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

+0

看到每个点的堆栈跟踪可能很有趣。 – leppie

+0

如何建议死锁一个线程?一切正在同步发生...... –

回答

1

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

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

在Erics示例中,有两个线程彼此等待。你只有一个线程,所以没有等待发生,因此:没有阻塞,没有死锁。

+0

啊,是的,这就是为什么我很愚蠢 - 当然我不能死锁一个执行线程 - 我可以像@pickypg说的那样产生一个不安全的场景。谢谢 – kmp

+0

静态构造函数是否在新线程中执行并且何时不会发生? –

+0

@zespri:请提供样本。 –

0

静态方法只被调用一次,一旦被加载,那些不被再次调用。 如果A.Initialize()方法称为B.Initialize()方法,反之亦然,这将是一个死锁。

因此,任何第一个加载到内存中的类都会被执行,然后之后调用它 - 因为类已经加载,所以静态块不会被执行。

+0

如果A.Initialize调用B.Initialize,反之亦然不会导致StackOverflowException,而不是死锁? – kmp

+0

,因为这里没有共同的资源,这两个类是指的,所以没有死锁的概念 - 唯一可能发生的是填补堆栈。 –

+0

这显然是递归,但没有死锁。 –

-3

该类实例实际上是在构造函数调用之前创建的,因此不需要再执行构造函数。

+0

我们在哪里创建对象首先是为了执行构造函数 - 因为我们只使用静态方法和静态块,所以没有构造函数的概念。 –

6

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

您在使用B时未使用A中的任何资源,反之亦然。因此,你的循环依赖是“安全的”,因为没有任何东西会爆炸。

如果你跟踪你的打印输出显示的路径,然后什么都不应该阻止:

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

,你真的做的唯一的事情就是本作的不安全状态的可能性:访问类,其构造无t完成执行。这是不安全的代码,虽然没有阻止,但肯定代表了一个破碎的状态。

1

为什么你认为应该有一个僵局。静态构造函数只被调用一次。无论执行语句B.Initialize();多少次,只会在引用B时第一次调用B类的静态构造函数。查看更多静态构造函数here

相关问题