views:

63

answers:

3

It is best to describe my question in an example:

  1. We create a Windows Event handle by CreateEvent, with manualReset as FALSE.
  2. We create 4 threads. Ensure that they all start running and waiting on the above event by WaitForSingleObject.
  3. In the main thread, in a for loop, we signal this event 4 times, by SetEvent. such as:

    for (int i = 0; i < 4; ++i) ::SetEvent(event);

My question is, can we say that all these 4 threads will certainly be waken up from waiting on this event?

According to my understanding of Windows Event, the answer is YES. Because when the event is set, there is always a thread waiting for it.

However, I read on MSDN that "Setting an event that is already set has no effect". Since the waiting threads probably do not get a chance to run while main thread setting event in the loop. Can they still be notified and reset the event to nonsignaled? If the event is not reset, the following SetEvent in the loop is obviously useless.

Or the OS kernel knows which thread should be notified when an event is set, and reset this event immediately if there is a waiting thread. So the waiting thread does not need to be schedule to reset the event to nonsignaled?

Any clarification or references are welcome. Thanks.

A: 

When you do SetEvent(event), since your manual reset is set as false for the event, any thread (windows doesnt specify any preferences) from one of the four would get passed the waitforsingleobject() and on the subsequent calls the other 3 threads would randomly be selected since your event is autoreset after releasing every thread.

If you're trying to imply the threads are re-entrant, the threads getting released every time would again be one out of four randomly by OSes choice.

Samrat Patil
+1  A: 

In a word? No.

There's no guarantee that each and every call to Set() will signal a waiting thread. MSDN describes this behavior as follows:

There is no guarantee that every call to the Set method will release a thread from an EventWaitHandle whose reset mode is EventResetMode::AutoReset. If two calls are too close together, so that the second call occurs before a thread has been released, only one thread is released. It is as if the second call did not happen. Also, if Set is called when there are no threads waiting and the EventWaitHandle is already signaled, the call has no effect. (Source)

If you want to ensure that a specific number of threads will be signaled, you should use a more suitable kind of synchronization primitive, such as a Semaphore.

Liran
Yes, Liran. You are right. Semaphore is the right way to ensure a specific number of threads to be waken up. I will consider it.
fzhang
+1  A: 

Because when the event is set, there is always a thread waiting for it.

No, you don't know that. A thread may indefinitely suspended for some reason just before the NtWaitForSingleObject system call.

Since the waiting threads probably do not get a chance to run while main thread setting event in the loop.

If a thread is waiting for an object, it doesn't run at all - that's the whole point of being able to block on a synchronization object.

Can they still be notified and reset the event to nonsignaled? If the event is not reset, the following SetEvent in the loop is obviously useless.

The thread that sets the event is the one that resets the signal state back to 0, not the thread that gets woken up. Of course, if there's no thread waiting the signal state won't be reset.

Or the OS kernel knows which thread should be notified when an event is set, and reset this event immediately if there is a waiting thread.

Yes, the kernel does know. Every dispatcher object has a wait list, and when a thread waits on an object it pushes a wait block onto that list.

wj32
Thanks, wj32. Your answer clears my mind about how a a thread is blocked on a synchronization primitive.
fzhang