[C# Basics] Easy to understand AutoResetEvent and ManualResetEvent

Thorough understanding of AutoResetEvent

AutoResetEvent is a thread synchronization primitive used to coordinate the execution order of threads in a multi-threaded environment. It is a synchronization mechanism provided by .NET Framework for communication and collaboration between threads.

AutoResetEvent maintains a state flag, which can be in one of two states, signaled or not signaled. A thread can control its own execution by waiting for a signal or setting a signal.

AutoResetEvent has two main methods: WaitOne and Set. Following are the functions and usage of these methods:

1. WaitOne:
   - When a thread calls the WaitOne method, it enters a waiting state until a signal is received.
   - If the AutoResetEvent is in the unsignaled state, the WaitOne method will block the execution of the thread.
   - If the AutoResetEvent is in the signaled state, the WaitOne method consumes the signal and puts the AutoResetEvent back into the unsignaled state.
   - You can specify the timeout time through the overloaded method of WaitOne, after the specified time, the thread will continue to execute without waiting for the signal.

2. Set:
   - When a thread calls the Set method, it sets the state of the AutoResetEvent to signaled.
   - If a thread is waiting for a signal, it will wake up and start executing.
   - If no threads are waiting for the signal, calling the Set method will also set the state of the AutoResetEvent to signaled, but will have no other effect.
   - Even if the Set method is called multiple times, the AutoResetEvent will only remain signaled once until consumed.

AutoResetEvent works like a door latch or a traffic light. A thread can block its own execution by waiting for the latch to open (WaitOne), while other threads can wake up the waiting thread by setting the latch to open (Set).

AutoResetEvent is very useful in multithreaded programming, especially when you need to control the execution order of threads or achieve cooperation between threads. It provides a simple and efficient way to synchronize the operations of threads and ensure that threads execute in the desired order.

 for example

Suppose there are two threads, one thread is responsible for producing items and the other thread is responsible for consuming items. These two threads need to be synchronized to ensure that the consumer can consume the item after the producer produces the item.

This synchronization can be easily achieved using AutoResetEvent. Here is a simple sample code:

using System;
using System.Threading;

class ProgramesetEvent producerEvent = new AutoResetEvent(false);
    static AutoResetEvent consumerEvent = new AutoResetEvent(true);

    static int item = 0;

    static void Main()
    {
        Thread p
{
    static AutoRonsumerThread = new Thread(ConsumeItems);

        producerroducerThread = new Thread(ProduceItems);
        Thread cThread.Start();
        consumerThread.Start();

        producerThread.Join();
        consumerThread.Join();

        Console.WriteLine("Finished");
    }

    static void ProduceItems()
    {
        for (int i = 0; i < 5; i++)
        {
            consumerEvent.WaitOne(); // 等待消费者消费物品

            // 生产物品
            item = i;
            Console.WriteLine("Produced item: " + item);

            producerEvent.Set(); // 发送信号给消费者
        }
    }

    static void ConsumeItems()
    {
        for (int i = 0; i < 5; i++)
        {
            producerEvent.WaitOne(); // 等待生产者生产物品

            // 消费物品
            Console.WriteLine("Consumed item: " + item);

            consumerEvent.Set(); // 发送信号给生产者
        }
    }
}

In this example, there is a shared `item` variable representing the item currently being produced or consumed. `producerEvent` controls the execution of producer threads, and `consumerEvent` controls the execution of consumer threads.

The producer thread enters the waiting state by calling `consumerEvent.WaitOne()` until the consumer thread consumes the item. Then, the producer thread generates a new item, stores it in the `item` variable, and calls `producerEvent.Set()` to send the signal to the consumer thread.

The consumer thread enters a wait state by calling `producerEvent.WaitOne()` until the producer thread produces items. Then, the consumer thread gets the item from the `item` variable and consumes it, and calls `consumerEvent.Set()` to send a signal to the producer thread.

In this way, producer and consumer threads can alternately produce and consume items and remain in sync with each other. The use of AutoResetEvent ensures correct sequential execution between producer and consumer threads, avoiding race conditions and data inconsistencies.

What are the parameters passed in by new AutoResetEvent used for?

The parameter passed in the constructor of AutoResetEvent is a Boolean value, which is used to specify the initial signal state. This parameter is called `initialState`.

- If `initialState` is `true`, the initial state of the AutoResetEvent is the signaled state. That is to say, the thread will not be blocked while waiting, but can execute directly. At this time, when the `WaitOne` method is called, if the AutoResetEvent is in the unsignaled state, the thread will continue execution immediately without waiting for the signal.

- If `initialState` is `false`, the initial state of the AutoResetEvent is the unsignaled state. That is, threads are blocked while waiting and cannot continue executing until a signal is received. At this time, when the `WaitOne` method is called, if the AutoResetEvent is in the unsignaled state, the thread will be blocked until the `Set` method is called to set it to the signaled state.

The initial signal state can be selected according to actual needs. If you want the thread to continue executing without being blocked at the beginning, you can use the signaled state; if you want the thread to wait for the signal to execute at the beginning, you can use the unsignaled state.

For example, in the producer-consumer example, the unsignaled state can be used as the initial state to ensure that the producer thread initially waits for a signal from the consumer thread to start producing items. This prevents producers from constantly producing new items when there are no consumers consuming them.

What is the difference between AutoResetEvent and ManualResetEvent

Both AutoResetEvent and ManualResetEvent are thread synchronization primitives used to coordinate the execution order of threads in a multithreaded environment, but there are some important differences between them.

1. Trigger method:
   - AutoResetEvent: After calling the `Set` method, only one waiting thread will be woken up and continue to execute, and then AutoResetEvent will automatically return to the no-signal state. That is, each call to the `Set` method only wakes up one waiting thread.
   - ManualResetEvent: After calling the `Set` method, all waiting threads are awakened and continue executing until the ManualResetEvent is set back to the unsignaled state by explicitly calling the `Reset` method. That is, each call to the `Set` method will wake up all waiting threads.

2. State reset:
   - AutoResetEvent: Automatically reset to no signal state. That is, when a thread waits for a signal and is woken up, AutoResetEvent will automatically reset itself to the no-signal state so that the next waiting thread can continue to wait.
   - ManualResetEvent: Requires an explicit call to the `Reset` method to reset it to the unsignaled state. That is, the ManualResetEvent will remain signaled until the `Reset` method is called to put it back to the unsignaled state.

3. Waiting method:
   - AutoResetEvent: When calling the `WaitOne` method, if the AutoResetEvent is in the unsignaled state, the thread will be blocked until the signal is received. If the AutoResetEvent is signaled, the thread consumes the signal and continues execution.
   - ManualResetEvent: When calling the `WaitOne` method, if the ManualResetEvent is in the unsignaled state, the thread will be blocked until the signal is received. Even if the ManualResetEvent is in the signaled state, the thread will consume the signal and continue execution without automatically resetting it to the unsignaled state.

According to these differences, you can choose to use AutoResetEvent or ManualResetEvent to adapt to different thread synchronization requirements.

- If you need to wake up only one waiting thread at a time, and you want the thread to automatically reset to the no-signal state after receiving a signal, you can use AutoResetEvent. This is useful for some scenarios where tasks are queued.
- If you need to wake up all waiting threads and want the thread to remain signaled after receiving a signal until it is reset to the unsignaled state by explicitly calling the Reset method, you can use ManualResetEvent. This is useful for some broadcast notification scenarios.

It is necessary to choose which synchronization primitive to use according to the specific application scenario and thread synchronization requirements.

summary

The principle of signal synchronization is to wait for the signal, pass through the signal state directly, and wait if there is no signal. What are you waiting for? By calling WaitOnce etc. Set sets the signal to have a signal, and ReSet sets the state to have no signal. AutoResetEvent will automatically become no signal after waiting! The opposite is ManualResetEven.

Manual translation is manual. Requires an explicit call to the `Reset` method to reset it to the unsignaled state.

Another key issue is the difference between multiple ones!

We can call WaitOnce many times in different threads through the same AutoResetEvent object.

In this way, many threads will wait for the same signal. Since AutoResetEvent automatically restores no signal, only one waiting thread will be awakened and continue to execute. Then this thread must be the first place to call WaitOnce, because once called WaitOnce and passed, AutoResetEvent automatically restores no signal. The rest will of course have to wait.

And ManualResetEven is manual, so it can wake up all of them.

Guess you like

Origin blog.csdn.net/songhuangong123/article/details/131591253