锁定获取和进一步锁定尝试不阻止:C#锁是否可以重入?

时间:2011-01-30 22:31:33

标签: c# .net multithreading concurrency deadlock

我已经编写了一个测试,我认为应该是一个有效的死锁案例。看来,一旦类的一个实例获得lock,该实例就不再需要重新获取lock,即使我明确尝试调用另一个应该{ {1}}再次。

这是班级:

lock

输出:

  

0没有死锁!
  1没有死锁!
  2没有死锁!
  3没有死锁!
  4没有死锁!
  5没有死锁!
  6没有死锁!
  7没有僵局!   8没有死锁!
  9没有死锁!

我原本以为这会导致僵局......任何人都能对此有所了解吗?

3 个答案:

答案 0 :(得分:42)

.NET中的锁是可重入的。仅阻止来自其他线程的收购。当同一个线程多次锁定同一个对象时,它只是增加一个计数器,并在释放时减少它。当计数器达到零时,锁定实际释放,以便从其他线程访问。

答案 1 :(得分:13)

Monitor,Mutex和ReaderWriterLock类维护具有线程关联的锁。 ReaderWriterLockSlim类允许您选择,它具有一个采用LockRecursionPolicy值的构造函数。使用LockRecursionPolicy.NoRecursion是一种优化,如果你的锁定非常细粒度,那么这是一个相当大的优化。

Semaphore类是一个没有任何线程关联的同步类。这段代码可靠地死锁:

class Tester {
    private Semaphore sem = new Semaphore(1, 1);
    public void TestLock() {
        sem.WaitOne();
        for (int i = 0; i < 10; i++) Deadlock(i);
        sem.Release();
    }

    private void Deadlock(int i) {
        if (!sem.WaitOne(100)) Console.WriteLine("deadlock!");
        else {
            sem.Release();
            Console.WriteLine("No deadlock!");
        }
    }
}

通常,线程仿射同步类需要两个线程和两个锁来解锁。标准模式是一个线程获取锁A和B,另一个线程获取B和A.顺序很重要。

.NET编程中存在不太明显的死锁情况,这是由锁无法看到的,因为它们内置于.NET框架代码中。一个非常经典的是BackgroundWorker。您可以在Busy属性上旋转的UI线程中编写代码,等待BGW完成。当BGW具有RunWorkerCompleted事件处理程序时,它总是会死锁。它在UI线程空闲之前无法运行,在事件处理程序运行完毕之前,BGW的Busy属性不会为false。

答案 2 :(得分:1)

在您的方案中,您在另一个锁中有锁。一旦代码命中“死锁”中的嵌套锁,“锁定(...)”代码基本上被忽略,因为它已经在“TestLock”中获取了它。

线程的重要来源:http://www.albahari.com/threading/part2.aspx