为什么使用繁忙等待的信号量会导致死锁?
问题描述:
我一直在实现自己的基本信号量,并注意到我选择的实现会影响我是否陷入僵局。但我不明白僵局是如何发生的。为什么使用繁忙等待的信号量会导致死锁?
我最初的实现(无死锁):
public synchronized void waitFor(){
value--;
if(value < 0)
wait();
}
public synchronized void signal(){
value++;
notify();
}
后来的实现(导致死锁):
public synchronized void waitFor(){
value--;
while(value < 0)
wait();
}
public synchronized void signal(){
value++;
notifyAll();
}
的等待()实际上是由一个try-catch在两组包围用于捕获线程中断的代码,但是为了便于阅读,我放弃了它,并假设它对死锁问题没有任何影响。
任何人有任何想法?
答
因为你是在后者的实施方式使用
while(value < 0)
wait();
,它是价值< 0的非无限循环中,它是循环这里永远。
这可能是您的死锁情况的指针。
+2
它不会循环,只有在其他线程调用'signal'之前。 – assylias 2013-03-16 14:17:07
答
我无法发现第二次执行的任何死锁风险。 while循环是等待锁定的正确选择(请参阅Object.wait() documentation中的虚假唤醒)。
此外,它看起来像没有信号操作可以错过。一个信号只能在另一个线程处于等待状态,或者没有其他线程正在运行waitFor()时发生。
因此,我建议你检查代码的其他部分:
- 是否所有的线程信号量的同一实例同步?
- 是否确定值计数器未在其他地方以 非线程安全方式使用?
- 当 他们完成时,是否所有线程调用sepmaphore.signal()? (通常这种释放操作放在finally块中)。
请使用信号量提供一个简短的*完整*程序来演示问题。 (我们不知道你是否有足够的线程发信号通知信号量,或者“this”是什么......) – 2013-03-16 14:10:58
我不知道如何只用一个锁就可以获得死锁......请注意,在你的第一个例子中你可能会错过一个信号,因为你使用'notify',并且你可能会因为你的等待不在一个循环内而早早起床。 – assylias 2013-03-16 14:14:45
最初的“价值”是什么? – jtahlborn 2013-03-16 14:17:11