AutoResetEvent
是线程同步原语,它允许一个线程通知另一个线程应当继续执行。这可以用于控制两个或多个线程的交互和执行顺序。
基本特性:
AutoResetEvent
具有两种状态:已设定(signaled)和未设定(non-signaled)。在设定状态下,它允许至少一个等待的线程继续执行。AutoResetEvent
在通过调用 Set()
方法变为设定状态后,当一个等待线程被释放以继续执行时,它将自动重置为未设定状态。这是它与ManualResetEvent
的主要区别,后者在设定状态下会释放所有等待的线程,而且状态不会自动重置,需要手动调用 Reset()
方法才能回到未设定状态。WaitOne()
方法来等待AutoResetEvent
的信号。如果AutoResetEvent
处于未设定状态,则调用 WaitOne()
的线程会被阻塞,直到AutoResetEvent
的状态通过调用 Set()
方法被设定。这使得你可以协调多个线程的工作,例如在"生产者-消费者"问题中,一个线程生成数据,而其他线程等待并处理这些数据。使用AutoResetEvent
可以确保数据在被处理之前已经完全生成。
AutoResetEvent
主要用于同步或协调多个线程,使它们能够按照预定的顺序执行或在某些条件满足后执行。以下是一些常见的使用场景:
AutoResetEvent
可用于控制何时可以添加或移除数据,以防止消费者在没有数据可取时尝试获取数据,或防止生产者在缓冲区已满时尝试添加数据。AutoResetEvent
来控制它们的执行顺序。每个线程都会在完成其工作后发出信号,以允许下一个线程开始执行。AutoResetEvent
。当事件发生(即任务完成)时,发出信号以唤醒等待的线程。优点
AutoResetEvent
可以方便地实现多个线程间的同步。AutoResetEvent
在释放等待的线程后会自动切换到非信号状态。这对于控制线程执行顺序或实现生产者-消费者模型非常有用。Set()
和Reset()
方法手动控制AutoResetEvent
的状态,以满足复杂的同步需求。缺点
Set()
方法只能唤醒一个等待的线程,即使有多个线程在等待。如果需要同时唤醒多个线程,可以考虑使用ManualResetEvent
。AutoResetEvent
在调用Set()
方法后立即重置为非信号状态,因此在高并发情况下可能会出现竞态条件,即有多个线程尝试在AutoResetEvent
设定之后立即获得执行权,但其中只有一个线程能成功,其余线程会因为AutoResetEvent
的状态被重置而继续等待。AutoResetEvent
没有公开的属性或方法可以用来查询当前是否在信号状态。要确定AutoResetEvent
的状态,必须调用WaitOne()
方法,并传入0毫秒的超时值,然后根据返回的布尔值来判断。这种设计可能对某些应用场景造成不便。主要工作原理基于操作系统的事件对象,用于在多个线程之间同步或协调。
以下是AutoResetEvent
的一些关键点:
AutoResetEvent
有两种状态:已设定(signaled)和未设定(non-signaled)。在已设定状态下,它允许一个等待的线程继续执行。在未设定状态下,它阻止一个或多个线程的执行,直到它被设定为已设定状态。WaitOne()
方法来等待事件的信号。如果AutoResetEvent
处于已设定状态,则第一个调用WaitOne()
的线程立即接收信号,然后AutoResetEvent
自动返回到未设定状态,并且其他任何尝试调用WaitOne()
的线程都将被阻塞,直到AutoResetEvent
再次被设定。Set()
方法将AutoResetEvent
设置为已设定状态。此时,如果有线程正等待这个事件的信号,那么其中的一个线程将被唤醒继续执行,同时AutoResetEvent
自动返回到未设定状态。Reset()
方法可以用来手动将AutoResetEvent
设置为未设定状态。AutoResetEvent
的主要工作原理是管理一个内部的布尔标志,该标志指示是否有线程可以执行,或者是否应该阻塞等待某个条件成立。
using System;
using System.Threading;
class Program
{
static AutoResetEvent autoEvent1 = new AutoResetEvent(true);
static AutoResetEvent autoEvent2 = new AutoResetEvent(false);
static void Main()
{
new Thread(PrintNumbers).Start();
new Thread(PrintLetters).Start();
Console.ReadLine();
}
static void PrintNumbers()
{
for (int i = 0; i < 10; i++)
{
autoEvent1.WaitOne(); // 等待信号
Console.WriteLine(i);
autoEvent2.Set(); // 发出信号
}
}
static void PrintLetters()
{
for (char letter = 'A'; letter < 'K'; letter++)
{
autoEvent2.WaitOne(); // 等待信号
Console.WriteLine(letter);
autoEvent1.Set(); // 发出信号
}
}
}
示例中,PrintNumbers
方法打印数字,然后通过调用 Set()
方法向 PrintLetters
方法发出信号,表示现在可以打印字母了。
与此同时,PrintNumbers
使用 WaitOne()
方法进入等待状态,等待 PrintLetters
完成打印并发出信号。同样,PrintLetters
方法也在打印字母后向 PrintNumbers
方法发出信号,并进入等待状态。
这样,两个线程就可以交替进行,直到操作完成。
https://learn.microsoft.com/en-us/dotnet/api/system.threading.autoresetevent?view=net-7.0&devlangs=csharp&f1url=%3FappId%3DDev16IDEF1%26l%3DEN-US%26k%3Dk(System.Threading.AutoResetEvent)%3Bk(DevLang-csharp)%26rd%3Dtrue