5

Delphi Docwiki 解释说,只要调用线程释放对象, Pulse就会通知等待队列中的下一个线程,它将能够锁定指定的对象。PulseAll向等待队列中的所有线程发出信号。

发现这段代码在线程队列实现中使用了 Pulse,并给出了上面的定义,认为应该使用 PulseAll - 或者以不同的方式询问:什么时候使用 Pulse 而不是 PulseAll 是正确的?(基本问题是:我如何确定“队列中的下一个线程”始终是需要通知的线程,除非在总共只有两个线程的琐碎情况下,或者代码可以安全假设唯一等待的线程是需要通知/“脉冲”的线程)?

function TSimpleThreadedQueue.Enqueue(const Item: T; Timeout: LongWord): TWaitResult;
begin
  if Closed then Exit(wrAbandoned);
  if not TMonitor.Enter(FQueue, Timeout) then Exit(wrTimeout);
  try
    if Closed then Exit(wrAbandoned);
    FQueue.Enqueue(Item);
    TMonitor.Pulse(FQueue);
    Result := wrSignaled;
  finally
    TMonitor.Exit(FQueue);
  end;
end;

对于Java语言中相应的同步方法,我发现了这个问题:Java: notify() vs. notifyAll() all over again


更新:上面链接的 Java 问题有一个有趣的答案,它显示了即使在只有两个方法 put 和 get 并且使用 notify()(Pulse() 的 Java 对应物)的生产者/消费者应用程序中也会发生死锁: Java: notify() vs. notifyAll() 再一次

答案包含建议

如果您不确定要使用哪个,请使用notifyAll.

4

1 回答 1

1

在传统的生产者/消费者队列中,每个消费者线程从队列中取出一项。当您将单个项目排入队列时,您只需要唤醒单个消费者线程。由于任何一个消费者线程都可以处理该任务,所以只要一个被唤醒,哪一个被唤醒并不重要。因此,调用Pulse()而不是PulseAll()就足够了。

于 2011-05-06T12:59:40.847 回答