我在Windows下运行的Delphi应用程序需要阻塞,直到另一个线程传递数据。换句话说,我需要等待一个同步对象,该对象来自我可以放入非信号状态的特定线程,就像另一个线程拥有该对象的所有权一样,这样当我调用 WaitFor()线程阻塞,直到其他线程之一解除阻塞(有多个潜在的线程可以解除阻塞并且事先不知道哪一个)。注意,所有线程都可以访问共享数据区域,因此访问公共同步对象不是问题。
我认为事件是正确的选择,直到我读到Raymond Chen关于PulseEvent()问题的这篇令人不安的博客文章:
http://blogs.msdn.com/b/oldnewthing/archive/2005/01/05/346888.aspx
实现此结果的正确同步技术是什么?如果您有一个Delphi或C / C ++示例的链接,那就太棒了。
答案 0 :(得分:2)
事件非常好,只是不要使用PulseEvent。微软不仅毫无希望地破坏了实施,而且其使用因固有的竞争条件而变得复杂。如果事件发生在线程阻塞事件之前,则事件将丢失。相反,请使用手动重置事件。
阻止:
B1)将事件设置为阻止。
B2)检查以确保事件尚未发生,并确保您要阻止它。如有必要,将事件放在共享数据结构中,唤醒我们的线程会注意到它。
B3)阻止活动。
醒来:
W1)更新共享数据以反映事件已发生的事实。
W2)取消阻止事件。如有必要,遍历共享数据结构并取消阻止与刚发生的事件相关的所有事件。
这里没有竞争条件。如果事件发生在B1或B2之后但在B3之前,则B3中的块实际上不会阻塞,因为W2将解除阻塞。如果事件已经在W1之前发生,那么线程将永远不会阻塞,因为B2将看到W1的效果,我们永远不会到达B3。
在大多数情况下,操作B2和W2需要在持有由处理此类事件的所有线程共享的锁的情况下完成。
答案 1 :(得分:0)
只需使用自动重置事件。请参阅CreateEvent函数的参数。每个需要等待的线程需要一个事件。只需调用SetEvent,而不是其他函数,如PulseEvent或ResetEvent。 WaitFor将自动重置事件。如果在调用WaitFor之前已经设置了事件,它将立即返回,重置事件。