2012-12-04 36 views
0

有三个线程和自动复位事件。 第二个和第三个线程正在等待这个事件,第一个线程调用两次SetEvent。 系统是否保证两个等待线程都会唤醒?是否每个调用SetEvent的autoreset事件都会唤醒一个线程?

我已阅读MSDN中有关.NET Framework AutoResetEvent类的注意事项: 无法保证每次调用Set方法都会释放线程。如果两个调用靠得太近,那么第二个调用在一个线程被释放之前发生,只有一个线程被释放。就好像第二个电话没有发生。

Win32 API是否正确?

回答

2

考虑以下方案:

Event Signaled | Thread 1 | Thread 2  | Thread 3 
--------------------------------------------------------- 
false   | SetEvent() |    |    
true   |   |    |    
true   |   | Wait Complete |    
false   |   |    |    
false   | SetEvent() |    |    
true   |   |    |    
true   |   |    | Wait Complete 
false   |   |    |    

成功

Event Signaled | Thread 1 | Thread 2  | Thread 3 
--------------------------------------------------------- 
false   | SetEvent() |    |    
true   |   |    | 
true   | SetEvent() |    |    
true   |   |    |    
true   |   | Wait Complete |    
false   |   |    |    
false   |   |    | Wait does not complete 
false   |   |    |  

失败

取决于哪个线程获得在特定的时间来执行,你可能会或可能不会完成等待其他线程。

您应该将事件更改为手动重置事件以确保所有线程都会完成等待,并在需要时使用ResetEvent将事件设置回非信号。

还有其他选择,例如使用semaphore来控制访问,或者如果您计划只等待很短的时间(旋转锁定性能),但是手动重置事件似乎是要走的路线,则可以使用critical section 。一般来说,请查看synchronization objects

+1

+1,ARE还有其他的失败机制 - 线程2可能运行两次,运行完其代码并循环回去,再次击中ARE并消耗等待。 MRE会立即将所有等待的线程准备就绪,如果所有线程都在等待,这很好。类似的问题会影响共享信号量 - 如果线程正在循环,向信号量发送两个单元并不能保证每个线程运行一次。如果要求所有其他线程的运行次数与线程1信号的次数完全一样多,我怀疑只有一个信号量数组才是确定的唯一方法。 –

+0

马丁詹姆斯+1。你提出了一些好的观点。也许OP会想要使用一组自动重置事件(每个线程一个),然后遍历并在'线程1'中发信号给它们。 – parrowdice