2013-03-16 59 views
0

我一直在实现自己的基本信号量,并注意到我选择的实现会影响我是否陷入僵局。但我不明白僵局是如何发生的。为什么使用繁忙等待的信号量会导致死锁?

我最初的实现(无死锁):

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在两组包围用于捕获线程中断的代码,但是为了便于阅读,我放弃了它,并假设它对死锁问题没有任何影响。

任何人有任何想法?

+1

请使用信号量提供一个简短的*完整*程序来演示问题。 (我们不知道你是否有足够的线程发信号通知信号量,或者“this”是什么......) – 2013-03-16 14:10:58

+0

我不知道如何只用一个锁就可以获得死锁......请注意,在你的第一个例子中你可能会错过一个信号,因为你使用'notify',并且你可能会因为你的等待不在一个循环内而早早起床。 – assylias 2013-03-16 14:14:45

+0

最初的“价值”是什么? – jtahlborn 2013-03-16 14:17:11

回答

-1

因为你是在后者的实施方式使用

while(value < 0) 
     wait(); 

,它是价值< 0的非无限循环中,它是循环这里永远。

这可能是您的死锁情况的指针。

+2

它不会循环,只有在其他线程调用'signal'之前。 – assylias 2013-03-16 14:17:07

0

我无法发现第二次执行的任何死锁风险。 while循环是等待锁定的正确选择(请参阅Object.wait() documentation中的虚假唤醒)。

此外,它看起来像没有信号操作可以错过。一个信号只能在另一个线程处于等待状态,或者没有其他线程正在运行waitFor()时发生。

因此,我建议你检查代码的其他部分:

  • 是否所有的线程信号量的同一实例同步?
  • 是否确定值计数器未在其他地方以 非线程安全方式使用?
  • 当 他们完成时,是否所有线程调用sepmaphore.signal()? (通常这种释放操作放在finally块中)。
相关问题