先介绍一下应用场景:
我有一个服务应用程序正在监视某物的状态,同时还有多个应用程序正在等待状态更改。一旦状态发生变化,每个应用程序将读取状态值(通过命名的 FileMap 对象)并执行相应的操作,然后等待状态再次发生变化。
所以我使用了一个命名的事件对象来做同步工作。所有应用程序都在等待此事件被发出信号,并且服务应用程序将设置此事件以在该状态更改时被发出信号。
我需要保证当状态改变时,每个等待的申请都会被释放并且只被释放一次!
这两种方法我都试过了
方法一
- 创建手动重置事件;
- 当状态改变时,先调用SetEvent,然后立即调用ResetEvent。
方法二
- 创建手动重置事件;
- 当状态改变时,调用 PulseEvent。
这两种方法在测试过程中似乎都很有效。但我认为它们都不可靠,因为:
对于##方法1 ##,在调用ResetEvent函数之前,可能一些等待线程没有机会执行。
对于##方法2##,微软声称PulseEvent is unreliable and should not be used .
这个案例有什么可行的解决方案吗?欢迎任何建议。
最佳答案
无法使用 O(1) 同步原语安全地实现这一点。
要通知 N 个应用程序有关新的状态更改,请使用 N 个事件。服务应设置它们,每个应用程序应在处理当前状态更改时重置其相应的事件。
要等待所有应用程序处理新的状态更改服务,可以使用另一组 N 个事件和带有 bWaitAll==TRUE 的 WaitForMultipleObjects。每个应用程序都应该设置它对应的事件。
因此,服务执行一个循环:观察状态变化,写入共享内存,设置所有 A 事件,等待所有 B 事件,重置所有 B 事件,继续循环。每个应用程序都执行一个循环:WAITING其 A(i) 事件、重置 A(i)、处理状态更改、设置 B(i)、继续循环。
A事件和B事件都可以是自动复位类型。然后您无需重置任何内容。
如果您觉得环保并且不想浪费资源,您可以使用某种反向信号量来代替 B 组事件。这可以通过一个由互斥量同步的共享计数器和一个通知服务的事件 (B') 来实现。服务不会等待整个 B 集,而是等待 B',当等待结束时将计数器设置为 N。每个应用程序不应设置其 B(i) 事件,而是应递减计数器,如果计数器降为零,则最后一个应用程序应仅设置 B'。
您无法绕过 A 组事件。问题不在于设置 A 事件,而在于重置。通过重置其 A(i) 事件,应用程序将不会错过另一个状态更改。并且在这里使用信号量也没有帮助。
请注意,此解决方案未考虑应用程序可能崩溃的情况。如果发生这种情况,该服务将永远等待不存在的应用程序响应。
关于windows - 关于 Win32 ##Event## 同步对象的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4322193/