问题如下,因为只使用down()调用屏障,以便等待n个线程到达,然后在关键区域中一起执行所有n个线程我可以通知调用 barrier.down 的线程,它现在可以继续。我尝试在 phase2()之后添加 notifyAll(),但这不起作用。救命? :)
public class cyclicBarrier {
private int n;
private int count;
private semaphore mutex;
private semaphore turnstile;
private semaphore turnstile2;
public cyclicBarrier(int n){
this.n = n;
this.count = 0;
this.mutex = new semaphore(1);
this.turnstile = new semaphore(0);
this.turnstile2 = new semaphore(0);
}
public synchronized void down() throws InterruptedException{
this.phase1(); //waits for n threads to arrive
this.phase2(); //waits for n threads to execute
}
private synchronized void phase1() throws InterruptedException {
this.mutex.down();
this.count++;
if(this.count == this.n){
for(int i = 0; i < this.n; i++){
this.turnstile.signal(); //when n threads received then move on to phase 2
}
}
this.mutex.signal();
this.turnstile.down(); //keeps waiting till I get n threads
}
private synchronized void phase2() throws InterruptedException {
this.mutex.down();
this.count--;
if(this.count == 0){
for(int i = 0; i < this.n; i++){
this.turnstile2.signal(); //reset the barrier for reuse
}
}
this.mutex.signal();
this.turnstile2.down(); //keeps waiting till n threads get executed
}
}
public class semaphore {
private int counter;
public semaphore(int number){
if (number > 0) {
this.counter = number;
}
}
public synchronized void signal(){
this.counter++;
notifyAll();
}
public synchronized void down() throws InterruptedException{
while (this.counter <= 0){
wait();
}
this.counter--;
}
}
答案 0 :(得分:1)
我看到您正在使用The Little Book of Semaphores中的解决方案。本书的一个要点是,您可以使用信号量作为唯一的协调原语来解决许多协调问题。使用 synchronized 来实现信号量是完全正确的,因为这是正确执行它所必需的。然而,它错过了在解决应该用信号量解决的谜题的方法中使用同步的观点。
另外,我认为在你的情况下它不起作用:你不能在 this.turnstile.down()上遇到僵局吗?你阻塞了一个信号量,该信号量在对象和方法上持有一个独占锁(通过同步),这将允许该信号量被释放。
如上所述解决问题:您向线程发出信号,告知他们可以通过 barrier.down()返回来继续。通过 turnstile.down()确保您不会太快返回。
除此之外:信号量实施
您的信号量实现看起来是正确的,除了您只允许非负的初始值,这至少是非标准的。这样做是否有动力让我无法看到?如果您认为负的初始值是错误的,为什么不抛出错误而不是默默地做其他事情呢?
旁白:其他同步原语
请注意,java构造同步, .wait()和 .notify()对应Monitor协调原语。用监视器(或其他协调原语)而不是信号量解决难题可能是有益的,但我建议将这些努力分开。我尝试使用Haskell's Software Transactional Memory解决难题时有点乐趣。
旁白:运行时
你说你已经尝试了一些东西,这表明你有一些代码允许你在问题中运行代码。如果您包含该代码会有所帮助,因此我们也可以轻松运行它。我可能会检查我的假设死锁实际发生了。