124

以下代码会导致在 .NET 上使用 C# 导致死锁吗?

 class MyClass
 {
    private object lockObj = new object();

    public void Foo()
    {
        lock(lockObj)
        { 
             Bar();
        }
    }

    public void Bar()
    {
        lock(lockObj)
        { 
          // Do something 
        }
    }       
 }
4

4 回答 4

156

不,只要您锁定同一个对象即可。递归代码实际上已经拥有锁,因此可以不受阻碍地继续执行。

lock(object) {...}是使用Monitor类的简写。正如Marc 指出的那样Monitor允许重新进入,因此重复尝试锁定当前线程已经拥有锁定的对象将正常工作。

如果您开始锁定不同的对象,那就是您必须小心的时候。特别注意:

  • 总是以相同的顺序在给定数量的对象上获取锁。
  • 始终以与获取锁相反的顺序释放锁。

如果你打破了这些规则中的任何一个,你几乎肯定会在某些时候遇到死锁问题。

这是一个描述 .NET 中线程同步的好网页:http ://dotnetdebug.ne​​t/2005/07/20/monitor-class-avoiding-deadlocks/

此外,一次锁定尽可能少的对象。尽可能考虑使用粗粒度锁。这个想法是,如果您可以编写代码以便有一个对象图并且您可以在该对象图的根上获取锁,那么就这样做。这意味着您在该根对象上拥有一个锁,因此不必担心获取/释放锁的顺序。

(进一步说明,您的示例在技术上不是递归的。要使其递归,Bar()必须调用自身,通常作为迭代的一部分。)

于 2008-12-24T17:44:09.733 回答
21

好吧,Monitor允许重新进入,所以你不能让自己陷入僵局......所以不:它不应该这样做

于 2008-12-24T17:44:42.977 回答
7

如果一个线程已经持有一个锁,那么它不会阻塞自己。.Net 框架确保了这一点。您只需确保两个线程不会尝试通过任何代码路径不按顺序获取相同的两个锁。

同一个线程可以多次获取同一个锁,但您必须确保释放锁的次数与获取锁的次数相同。当然,只要您使用“lock”关键字来完成此操作,它就会自动发生。

于 2008-12-24T18:01:01.213 回答
5

不,这段代码不会有死锁。如果您真的想创建死锁,最简单的一个需要至少 2 个资源。考虑狗和骨头的场景。1. 一只狗可以完全控制一根骨头,因此任何其他狗都必须等待。2. 最少需要2只2块骨头的狗,分别锁定自己的骨头并寻找其他骨头时造成僵局。

.. 等等 n 狗和 m 骨头,并导致更复杂的死锁。

于 2012-01-14T18:36:12.160 回答