C# AutoResetEvent线程信号

1.概要

什么是AutoResetEvent?

AutoResetEvent是线程同步原语,它允许一个线程通知另一个线程应当继续执行。这可以用于控制两个或多个线程的交互和执行顺序。

基本特性:

  • AutoResetEvent具有两种状态:已设定(signaled)和未设定(non-signaled)。在设定状态下,它允许至少一个等待的线程继续执行。

  • AutoResetEvent在通过调用 Set() 方法变为设定状态后,当一个等待线程被释放以继续执行时,它将自动重置为未设定状态。这是它与ManualResetEvent的主要区别,后者在设定状态下会释放所有等待的线程,而且状态不会自动重置,需要手动调用 Reset() 方法才能回到未设定状态。

  • 线程可以通过调用 WaitOne() 方法来等待AutoResetEvent的信号。如果AutoResetEvent处于未设定状态,则调用 WaitOne() 的线程会被阻塞,直到AutoResetEvent的状态通过调用 Set() 方法被设定。

这使得你可以协调多个线程的工作,例如在"生产者-消费者"问题中,一个线程生成数据,而其他线程等待并处理这些数据。使用AutoResetEvent可以确保数据在被处理之前已经完全生成。

使用场景是什么?

AutoResetEvent主要用于同步或协调多个线程,使它们能够按照预定的顺序执行或在某些条件满足后执行。以下是一些常见的使用场景:

  1. 生产者-消费者模型:在这种模型中,两个或更多的线程共享一个数据缓冲区或队列。一个线程(生产者)向缓冲区添加数据,另一个线程(消费者)从缓冲区取出数据进行处理。AutoResetEvent可用于控制何时可以添加或移除数据,以防止消费者在没有数据可取时尝试获取数据,或防止生产者在缓冲区已满时尝试添加数据。

  2. 控制线程执行顺序:如果你有几个线程需要按特定顺序执行,你可以使用AutoResetEvent来控制它们的执行顺序。每个线程都会在完成其工作后发出信号,以允许下一个线程开始执行。

  3. 等待一次性事件:如果一个线程需要等待另一个线程完成特定任务后才能继续执行,则可以使用AutoResetEvent。当事件发生(即任务完成)时,发出信号以唤醒等待的线程。

优缺点是什么?

优点

  1. 简单易用:使用AutoResetEvent可以方便地实现多个线程间的同步。

  2. 自动重置AutoResetEvent在释放等待的线程后会自动切换到非信号状态。这对于控制线程执行顺序或实现生产者-消费者模型非常有用。

  3. 灵活可控:你可以通过Set()Reset()方法手动控制AutoResetEvent的状态,以满足复杂的同步需求。

缺点

  1. 只能唤醒一个线程:每次调用Set()方法只能唤醒一个等待的线程,即使有多个线程在等待。如果需要同时唤醒多个线程,可以考虑使用ManualResetEvent

  2. 可能引发竞态条件:由于AutoResetEvent在调用Set()方法后立即重置为非信号状态,因此在高并发情况下可能会出现竞态条件,即有多个线程尝试在AutoResetEvent设定之后立即获得执行权,但其中只有一个线程能成功,其余线程会因为AutoResetEvent的状态被重置而继续等待。

  3. 没有提供查询状态的方法AutoResetEvent没有公开的属性或方法可以用来查询当前是否在信号状态。要确定AutoResetEvent的状态,必须调用WaitOne()方法,并传入0毫秒的超时值,然后根据返回的布尔值来判断。这种设计可能对某些应用场景造成不便。

基础原理:

主要工作原理基于操作系统的事件对象,用于在多个线程之间同步或协调。

以下是AutoResetEvent的一些关键点:

  • AutoResetEvent有两种状态:已设定(signaled)和未设定(non-signaled)。在已设定状态下,它允许一个等待的线程继续执行。在未设定状态下,它阻止一个或多个线程的执行,直到它被设定为已设定状态。

  • 线程通过调用WaitOne()方法来等待事件的信号。如果AutoResetEvent处于已设定状态,则第一个调用WaitOne()的线程立即接收信号,然后AutoResetEvent自动返回到未设定状态,并且其他任何尝试调用WaitOne()的线程都将被阻塞,直到AutoResetEvent再次被设定。

  • 当你希望一个线程继续执行时,可以调用Set()方法将AutoResetEvent设置为已设定状态。此时,如果有线程正等待这个事件的信号,那么其中的一个线程将被唤醒继续执行,同时AutoResetEvent自动返回到未设定状态。

  • Reset()方法可以用来手动将AutoResetEvent设置为未设定状态。

AutoResetEvent的主要工作原理是管理一个内部的布尔标志,该标志指示是否有线程可以执行,或者是否应该阻塞等待某个条件成立。

2.详细内容

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 方法发出信号,并进入等待状态。

这样,两个线程就可以交替进行,直到操作完成。

569b525c497fddf946bd3c54b1c6cb69.png

ref

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值