我已经编写了一个测试,我认为应该是一个有效的死锁案例。看来,一旦类的一个实例获得lock
,该实例就不再需要重新获取lock
,即使我明确尝试调用另一个应该{ {1}}再次。
这是班级:
lock
输出:
0没有死锁!
1没有死锁!
2没有死锁!
3没有死锁!
4没有死锁!
5没有死锁!
6没有死锁!
7没有僵局! 8没有死锁!
9没有死锁!
我原本以为这会导致僵局......任何人都能对此有所了解吗?
答案 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”中获取了它。