EventWaitHandle, AutoResetEvent, and ManualResetEvent
Event wait handles allow threads to synchronize their activities by signaling each other and by waiting for signals. Event wait handles (also referred to simply as events) can be signaled in order to release one or more waiting threads. After it is signaled, an event wait handle is reset either manually (ManualResetEvent) or automatically (AutoResetEvent). EventWaitHandle is the base class of ManualResetEvent and AutoResetEvent, which inherit its Set and Reset methods. In Silverlight, the EventWaitHandle class represents a local event wait handle (local event).
Event wait handles are not events in the sense usually meant by that word in the .NET Framework. There are no delegates or event handlers involved. The word "event" is used to describe them because they have traditionally been referred to as operating-system events, and because the act of signaling the wait handle indicates to waiting threads that an event has occurred.
Event wait handles are useful in many of the same synchronization scenarios as the Monitor class. Event wait handles are often easier to use than the Monitor.Wait and Monitor.Pulse methods, and they offer more control over signaling. For more information see Synchronization Primitives.
Event wait handles use system synchronization objects, which are protected by SafeWaitHandle wrappers to ensure that the resources are released. You can use the IDisposable.Dispose method to free the resources immediately when you have finished using the object.
You create an automatic reset event by creating an AutoResetEvent object, which is derived from EventWaitHandle. As its name implies, this synchronization event resets automatically when it is signaled, after it releases a single waiting thread. Signal the event by calling its Set method.
Automatic reset events are generally used to provide exclusive access to a resource for a single thread at a time. A thread requests the resource by calling the WaitOne method. If no other thread is holding the wait handle, the method returns true and the calling thread has control of the resource.
As with all synchronization mechanisms, you must ensure that all code paths wait on the appropriate wait handle before accessing a protected resource. Thread synchronization is cooperative.
If an automatic reset event is signaled when no threads are waiting, it remains signaled until a thread attempts to wait on it. The event releases the thread and immediately resets to non-signaled, blocking subsequent threads.
You create a manual reset event by creating a ManualResetEvent object, which is also derived from EventWaitHandle. As its name implies, this synchronization event must be reset manually after it has been signaled. Until you reset a manual resent event by calling its Reset method, threads that wait on the event handle proceed immediately without blocking.
A manual reset event acts like the gate of a corral. When the event is not signaled, threads that wait on it block, like horses in a corral. When the event is signaled, by calling its Set method, all waiting threads are free to proceed. The event remains signaled until its Reset method is called. This makes the manual reset event an ideal way to hold up threads that need to wait until one thread finishes a task.
Like horses leaving a corral, it takes time for the released threads to be scheduled by the operating system and to resume execution. If the Reset method is called before all the threads have resumed execution, the remaining threads once again block. Which threads resume and which threads block depends on random factors like the load on the system, the number of threads waiting for the scheduler, and so on. This is not a problem if the thread that signals the event ends after signaling, which is the most common usage pattern. If you want the thread that signaled the event to begin a new task after all the waiting threads have resumed, you must block it until all the waiting threads have resumed. Otherwise, you have a race condition, and the behavior of your code becomes unpredictable.
Typically, one or more threads block on an EventWaitHandle by calling the WaitOne method (inherited from WaitHandle), and remain blocked until an unblocked thread calls the Set method, which releases one of the waiting threads (in the case of automatic reset events) or all of them (in the case of manual reset events).