AutoResetEvent使用示例

19

title: AutoResetEvent 线程同步
description:
published: true
date: 2024-11-09T03:15:47.110Z
tags:
editor: markdown

dateCreated: 2024-11-09T03:15:47.110Z

AutoResetEvent 是 .NET Framework 中用于同步线程操作的一个同步基元。它维护了一个内部信号状态,该状态可以通过调用 Set 方法设置为有信号(signaled),也可以通过调用 WaitOne 方法等待或阻塞线程,直到该信号状态变为有信号。
官方:https://learn.microsoft.com/zh-cn/dotnet/api/system.threading.autoresetevent?view=net-8.0

使用场景

AutoResetEvent 的使用场景主要包括:

  1. 线程同步:当你需要控制线程的执行顺序或协调它们对共享资源的访问时,可以使用 AutoResetEvent
  2. 生产者-消费者问题:在多线程编程中,生产者线程生产数据,消费者线程消费数据。AutoResetEvent 可以用来控制生产者和消费者之间的同步。
  3. 限制并发执行:如果你需要限制同时执行某段代码的线程数量,可以使用多个 AutoResetEvent 来控制。
  4. 信号通知:一个线程可以通过 AutoResetEvent 向其他线程发出信号,通知它们某个条件已经满足。

    使用示例

    以下是一个使用 AutoResetEvent 的简单示例,演示了生产者-消费者问题的解决方案:
    using System;
    using System.Threading;
    class Program
    {
    // 创建一个初始状态为无信号的 AutoResetEvent
    static AutoResetEvent autoResetEvent = new AutoResetEvent(false);
    static void Main(string[] args)
    {
        // 启动消费者线程
        Thread consumerThread = new Thread(Consume);
        consumerThread.Start();
        // 生产者线程
        for (int i = 0; i < 5; i++)
        {
            Console.WriteLine("生产者正在生产数据...");
            // 模拟生产数据需要一些时间
            Thread.Sleep(1000);
            // 设置 AutoResetEvent 信号,通知消费者数据已经准备好了
            autoResetEvent.Set();
            // 生产完成后,等待消费者处理完成
            autoResetEvent.WaitOne();
        }
        // 完成所有生产后,不再需要消费者线程
        consumerThread.Join();
    }
    static void Consume()
    {
        while (true)
        {
            // 等待生产者的信号
            autoResetEvent.WaitOne();
    
            Console.WriteLine("消费者正在消费数据...");
            // 模拟消费数据需要一些时间
            Thread.Sleep(1000);
            // 消费完成后,重置信号状态,允许生产者继续生产
            autoResetEvent.Set();
        }
    }
    }
    
    在这个示例中:
  5. 生产者每生产一个数据项后,会调用 Set 方法来发出信号,通知消费者数据已经准备好。
  6. 消费者通过调用 WaitOne 方法等待生产者的信号。一旦收到信号,消费者消费数据,然后再次调用 Set 方法来重置信号状态,以便生产者可以继续生产。
  7. 循环继续,直到生产者完成所有生产任务。
    请注意,AutoResetEvent 在每次 Set 调用后会自动重置为无信号状态,因此每个 Set 调用只能释放一个等待线程。如果多个线程在等待同一个 AutoResetEvent,那么第一个收到信号的线程将解除阻塞,而其他线程仍然保持阻塞状态,直到下一次 Set 被调用。

微软官方例子:

using System;
using System.Threading;

// Visual Studio: Replace the default class in a Console project with 
//                the following class.
class Example
{
    private static AutoResetEvent event_1 = new AutoResetEvent(true);
    private static AutoResetEvent event_2 = new AutoResetEvent(false);

    static void Main()
    {
        Console.WriteLine("Press Enter to create three threads and start them.\r\n" +
                          "The threads wait on AutoResetEvent #1, which was created\r\n" +
                          "in the signaled state, so the first thread is released.\r\n" +
                          "This puts AutoResetEvent #1 into the unsignaled state.");
        Console.ReadLine();

        for (int i = 1; i < 4; i++)
        {
            Thread t = new Thread(ThreadProc);
            t.Name = "Thread_" + i;
            t.Start();
        }
        Thread.Sleep(250);

        for (int i = 0; i < 2; i++)
        {
            Console.WriteLine("Press Enter to release another thread.");
            Console.ReadLine();
            event_1.Set();
            Thread.Sleep(250);
        }

        Console.WriteLine("\r\nAll threads are now waiting on AutoResetEvent #2.");
        for (int i = 0; i < 3; i++)
        {
            Console.WriteLine("Press Enter to release a thread.");
            Console.ReadLine();
            event_2.Set();
            Thread.Sleep(250);
        }

        // Visual Studio: Uncomment the following line.
        //Console.Readline();
    }

    static void ThreadProc()
    {
        string name = Thread.CurrentThread.Name;

        Console.WriteLine("{0} waits on AutoResetEvent #1.", name);
        event_1.WaitOne();
        Console.WriteLine("{0} is released from AutoResetEvent #1.", name);

        Console.WriteLine("{0} waits on AutoResetEvent #2.", name);
        event_2.WaitOne();
        Console.WriteLine("{0} is released from AutoResetEvent #2.", name);

        Console.WriteLine("{0} ends.", name);
    }
}

/* This example produces output similar to the following:

Press Enter to create three threads and start them.
The threads wait on AutoResetEvent #1, which was created
in the signaled state, so the first thread is released.
This puts AutoResetEvent #1 into the unsignaled state.

Thread_1 waits on AutoResetEvent #1.
Thread_1 is released from AutoResetEvent #1.
Thread_1 waits on AutoResetEvent #2.
Thread_3 waits on AutoResetEvent #1.
Thread_2 waits on AutoResetEvent #1.
Press Enter to release another thread.

Thread_3 is released from AutoResetEvent #1.
Thread_3 waits on AutoResetEvent #2.
Press Enter to release another thread.

Thread_2 is released from AutoResetEvent #1.
Thread_2 waits on AutoResetEvent #2.

All threads are now waiting on AutoResetEvent #2.
Press Enter to release a thread.

Thread_2 is released from AutoResetEvent #2.
Thread_2 ends.
Press Enter to release a thread.

Thread_1 is released from AutoResetEvent #2.
Thread_1 ends.
Press Enter to release a thread.

Thread_3 is released from AutoResetEvent #2.
Thread_3 ends.
 */