AutoResetEvent vs ManualResetEvent in C
In multi-threaded C# programming, thread signaling is a
synchronization mechanism that allows one thread to notify one or more
other threads that a specific operation has completed or an event has
occurred. The .NET runtime provides AutoResetEvent and
ManualResetEvent as two core synchronization primitives
derived from EventWaitHandle to coordinate these
interactions. While both classes use boolean states—signaled (true) and
non-signaled (false)—to control thread execution via methods like
WaitOne(), Set(), and Reset(),
they differ fundamentally in how they transition between these states
and how many waiting threads they release.
Understanding Thread Signaling Basics
Thread signaling works like a traffic light or a gate for threads.
When a thread calls WaitOne(), it pauses execution and
enters a wait state until the handle is placed in a signaled state.
Another thread signals the waiting thread by calling Set().
Calling Reset() manually returns the handle to an
unsignaled state, causing subsequent threads that call
WaitOne() to block.
AutoResetEvent: Automatic State Reset
An AutoResetEvent functions like a turnstile. When
Set() is called, it transitions to a signaled state, allows
exactly one waiting thread to pass through, and then
immediately and automatically resets to the unsignaled state.
- Behavior: Only a single thread is released per
Set()call, even if multiple threads are currently blocked onWaitOne(). - State Management: You do not need to call
Reset()manually because the system resets the state automatically as soon as a waiting thread is released. - No Waiters: If
Set()is called when no threads are waiting, the handle remains signaled until the next thread callsWaitOne(). That thread will proceed immediately without blocking, and the event will automatically reset to unsignaled.
AutoResetEvent autoEvent = new AutoResetEvent(false);
// Worker thread
void Worker()
{
autoEvent.WaitOne(); // Blocks until Set() is called
// Executes work; event automatically resets to unsignaled
}
// Main thread
autoEvent.Set(); // Releases exactly one waiting worker threadManualResetEvent: Manual State Reset
A ManualResetEvent behaves like an open gate. When
Set() is called, the event enters the signaled state and
remains signaled until it is explicitly reset by calling
Reset().
- Behavior: Once signaled, all
waiting threads are released simultaneously. Any subsequent threads that
call
WaitOne()will pass through without blocking as long as the event remains in the signaled state. - State Management: You must explicitly call
Reset()to close the gate and force future threads callingWaitOne()to wait again. - Broadcast Capability: It is primarily used for broadcast signaling, where multiple consumer threads need to wait for a shared prerequisite, such as application initialization or cache loading, to complete.
ManualResetEvent manualEvent = new ManualResetEvent(false);
// Worker threads
void Worker()
{
manualEvent.WaitOne(); // All waiting threads are released when Set() is called
// Executes work
}
// Main thread
manualEvent.Set(); // Releases ALL currently waiting worker threads
// State remains signaled until Reset() is called
manualEvent.Reset(); // Blocks any new threads calling WaitOne()Key Differences Summary
| Feature | AutoResetEvent | ManualResetEvent |
|---|---|---|
| Reset Behavior | Automatically resets to unsignaled after releasing one thread. | Remains signaled until
Reset() is explicitly invoked. |
| Threads Released | Releases only one thread per
Set() invocation. |
Releases all waiting threads when
Set() is invoked. |
| Ideal Use Case | Exclusive handoffs, rate-limiting, and producer-consumer workflows. | Broadcast signaling, system readiness, and batch processing triggers. |
When to Use Which
Use AutoResetEvent when implementing
exclusive task handoffs or resource-sharing scenarios where only one
thread should proceed at a time (e.g., a producer signaling a consumer
that a single item is ready for processing).
Use ManualResetEvent (or its modern,
lightweight alternative, ManualResetEventSlim) when an
event must notify multiple threads at once to start execution
simultaneously, or when a component must signal that a one-time setup
process has finished.