AutoResetEvent使用示例
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
的使用场景主要包括:
- 线程同步:当你需要控制线程的执行顺序或协调它们对共享资源的访问时,可以使用
AutoResetEvent
。 - 生产者-消费者问题:在多线程编程中,生产者线程生产数据,消费者线程消费数据。
AutoResetEvent
可以用来控制生产者和消费者之间的同步。 - 限制并发执行:如果你需要限制同时执行某段代码的线程数量,可以使用多个
AutoResetEvent
来控制。 - 信号通知:一个线程可以通过
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(); } } }
- 生产者每生产一个数据项后,会调用
Set
方法来发出信号,通知消费者数据已经准备好。 - 消费者通过调用
WaitOne
方法等待生产者的信号。一旦收到信号,消费者消费数据,然后再次调用Set
方法来重置信号状态,以便生产者可以继续生产。 - 循环继续,直到生产者完成所有生产任务。
请注意,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.
*/