【C#基础】轻松理解AutoResetEvent 和 ManualResetEvent

这篇具有很好参考价值的文章主要介绍了【C#基础】轻松理解AutoResetEvent 和 ManualResetEvent。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

彻底理解AutoResetEvent

AutoResetEvent 是一个线程同步原语,用于在多线程环境中协调线程的执行顺序。它是.NET Framework提供的一种同步机制,用于线程间的通信和协作。

AutoResetEvent 维护了一个状态标志,可以处于有信号或无信号两种状态之一。线程可以通过等待信号或设置信号来控制自己的执行。

AutoResetEvent 具有两个主要方法:WaitOne 和 Set。以下是这些方法的功能和用法:

1. WaitOne:
   - 当线程调用 WaitOne 方法时,它会进入等待状态,直到接收到信号。
   - 如果 AutoResetEvent 处于无信号状态,WaitOne 方法将阻塞线程的执行。
   - 如果 AutoResetEvent 处于有信号状态,WaitOne 方法将消耗该信号,并使 AutoResetEvent 重新进入无信号状态。
   - 可以通过 WaitOne 的重载方法指定超时时间,在超过指定时间后,线程将继续执行而不等待信号。

2. Set:
   - 当线程调用 Set 方法时,它会将 AutoResetEvent 的状态设置为有信号。
   - 如果有线程正在等待信号,它将被唤醒并开始执行。
   - 如果没有线程在等待信号,调用 Set 方法也会将 AutoResetEvent 的状态设置为有信号,但不会有任何其他影响。
   - 即使多次调用 Set 方法,AutoResetEvent 也只会保持有信号状态一次,直到被消耗。

AutoResetEvent 的工作方式可以类比于一个门闩或红绿灯。线程可以通过等待门闩打开(WaitOne)来阻塞自己的执行,而其他线程则可以通过设置门闩打开(Set)来唤醒等待的线程。

AutoResetEvent 在多线程编程中非常有用,特别是在需要控制线程的执行顺序或实现线程间的协作时。它提供了一种简单而有效的方式来同步线程的操作,并确保线程按照期望的顺序执行。

 举个例子

假设有两个线程,一个线程负责生产物品,另一个线程负责消费物品。这两个线程需要进行同步,以确保在生产者生成物品后,消费者才能消费物品。

使用 AutoResetEvent 可以很方便地实现这种同步。下面是一个简单的示例代码:

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(); // 发送信号给生产者
        }
    }
}

在这个示例中,有一个共享的 `item` 变量表示当前要生产或消费的物品。`producerEvent` 控制生产者线程的执行,而 `consumerEvent` 控制消费者线程的执行。

生产者线程通过调用 `consumerEvent.WaitOne()` 进入等待状态,直到消费者线程消费完物品。然后,生产者线程生成一个新的物品,将其存储在 `item` 变量中,并调用 `producerEvent.Set()` 发送信号给消费者线程。

消费者线程通过调用 `producerEvent.WaitOne()` 进入等待状态,直到生产者线程生成物品。然后,消费者线程从 `item` 变量中获取物品并进行消费,并调用 `consumerEvent.Set()` 发送信号给生产者线程。

通过这种方式,生产者和消费者线程可以交替地生产和消费物品,并且彼此之间保持同步。AutoResetEvent 的使用确保了生产者和消费者线程之间的正确顺序执行,避免了竞态条件和数据不一致的问题。

new AutoResetEvent 传入的参数是干嘛用的呢?

在 AutoResetEvent 的构造函数中传入的参数是一个布尔值,用于指定初始的信号状态。这个参数被称为 `initialState`。

- 如果 `initialState` 为 `true`,则 AutoResetEvent 的初始状态为有信号状态。也就是说,线程在等待时不会被阻塞,而是可以直接执行。此时,调用 `WaitOne` 方法时,如果 AutoResetEvent 处于无信号状态,则线程将立即继续执行,不会等待信号。

- 如果 `initialState` 为 `false`,则 AutoResetEvent 的初始状态为无信号状态。也就是说,线程在等待时会被阻塞,直到收到信号才能继续执行。此时,调用 `WaitOne` 方法时,如果 AutoResetEvent 处于无信号状态,则线程将被阻塞,直到调用 `Set` 方法将其置为有信号状态。

可以根据实际需求来选择初始的信号状态。如果希望线程在开始时能够继续执行而不被阻塞,可以使用有信号状态;如果希望线程在开始时等待信号才能执行,可以使用无信号状态。

例如,在生产者-消费者示例中,可以使用无信号状态作为初始状态,以确保生产者线程在开始时等待消费者线程的信号才能开始生产物品。这样可以避免生产者在没有消费者消费物品时不断生成新物品。

AutoResetEvent 和 ManualResetEvent 有啥区别

AutoResetEvent 和 ManualResetEvent 都是线程同步原语,用于在多线程环境中协调线程的执行顺序,但它们之间有一些重要的区别。

1. 触发方式:
   - AutoResetEvent:在调用 `Set` 方法后,只有一个等待线程会被唤醒并继续执行,然后 AutoResetEvent 会自动恢复为无信号状态。即每次调用 `Set` 方法只唤醒一个等待线程。
   - ManualResetEvent:在调用 `Set` 方法后,所有等待线程都会被唤醒并继续执行,直到显式调用 `Reset` 方法将 ManualResetEvent 设置回无信号状态为止。即每次调用 `Set` 方法会唤醒所有等待线程。

2. 状态重置:
   - AutoResetEvent:自动重置为无信号状态。即当一个线程等待信号并被唤醒后,AutoResetEvent 会自动将自身重置为无信号状态,以便下一个等待的线程能够继续等待。
   - ManualResetEvent:需要显式调用 `Reset` 方法将其重置为无信号状态。即 ManualResetEvent 会保持有信号状态,直到调用 `Reset` 方法将其置回无信号状态。

3. 等待方式:
   - AutoResetEvent:在调用 `WaitOne` 方法时,如果 AutoResetEvent 处于无信号状态,线程会被阻塞直到接收到信号。如果 AutoResetEvent 处于有信号状态,线程会消耗该信号并继续执行。
   - ManualResetEvent:在调用 `WaitOne` 方法时,如果 ManualResetEvent 处于无信号状态,线程会被阻塞直到接收到信号。即使 ManualResetEvent 处于有信号状态,线程也会消耗该信号并继续执行,而不会自动将其重置为无信号状态。

根据这些区别,可以选择使用 AutoResetEvent 或 ManualResetEvent 来适应不同的线程同步需求。

- 如果需要每次只唤醒一个等待线程,并且希望线程在接收到信号后自动重置为无信号状态,可以使用 AutoResetEvent。这对于一些排队任务的场景很有用。
- 如果需要唤醒所有等待线程,并且希望线程在接收到信号后保持有信号状态,直到显式调用 Reset 方法将其重置为无信号状态,可以使用 ManualResetEvent。这对于一些广播通知的场景很有用。

需要根据具体的应用场景和线程同步需求来选择使用哪种同步原语。

小结

信号同步的原理就是等待信号,有信号状态直接过,无信号就等。怎么等?通过调用WaitOnce等。Set设置信号为有信号,ReSet设置状态为无信号。AutoResetEvent就是等完之后会自动变成无信号!与之相反是ManualResetEven。

Manual翻译过来就是手动。需要显式调用 `Reset` 方法将其重置为无信号状态。

还有一个关键的问题是多个一个的区别!

我们可以的通过 同一个AutoResetEvent 对象 在不同的线程里调用很多次WaitOnce。

这样就会又很多个线程等待同一个信号,由于AutoResetEvent是自动恢复无信号的,所以只有一个等待线程会被唤醒并继续执行,那这一个线程肯定是最先调用WaitOnce的地方,因为一旦调用了WaitOnce并通过了,AutoResetEvent自动恢复无信号。其他的当然得继续等咯。

而 ManualResetEven 是手动的,所以能唤醒所有的。文章来源地址https://www.toymoban.com/news/detail-541167.html

到了这里,关于【C#基础】轻松理解AutoResetEvent 和 ManualResetEvent的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 轻松理解期权的交易基础:看涨VS看跌期权

    期权最重要的一个概念就是通过期权合约来买卖未来某个标的资产的权利,一般投资者都是通过期权买卖某个标的资产的上涨与下跌来获得差价利润。 很多人不理解期权是怎么个交易模式,因为期权的报价跟传统的股票报价很不一样,下面是50ETF期权的报价图,呈现的是像

    2024年01月18日
    浏览(32)
  • C#基础——语法学习

    在介绍基本语法之前我们先来大概讲一下创建好的这些文件都是做什么的 常用快捷键 ctrl + k + d :快速对其代码 ctrl + k + c :注释代码 ctrl + k + u :取消注释代码 f1:查看帮助文档 C# 提供了三种注释方式 1.单行注释 2.多行注释 3.标注 C#语法中内置了数据类型,分为了三类 1.值

    2024年02月04日
    浏览(37)
  • 二、C#基础语法( 控制结构)

    在C#中,控制结构用于控制程序的流程,决定了代码的执行顺序。C#支持以下几种主要的控制结构: 条件语句 :根据某个条件(布尔表达式)来决定执行的代码块。 循环语句 :重复执行一段代码,直到满足某个条件。 跳转语句 :改变程序的执行流程。 异常处理 :用于捕获

    2024年02月04日
    浏览(35)
  • MOS管基础知识:轻松理解MOS管工作原理

    MOS管 是一种利用电场效应来控制其电流大小的半导体三端器件,很多特性和应用方向都与三极管类似。这种器件不仅体积小、质量轻、耗电省、寿命长、而且还具有输入阻抗高、噪声低、热稳定性好、抗辐射能力强等优点,应用广泛,特别是在大规模的集成电路中。 根据导

    2024年02月08日
    浏览(42)
  • 深入理解 C++ 语法:从基础知识到高级应用

    让我们将以下代码分解以更好地理解它: 示例 示例解释 第 1 行: #include iostream 是一个头文件库,它让我们可以使用输入和输出对象,比如 cout (在第 5 行使用)。头文件为 C++ 程序添加功能。 第 2 行: using namespace std 表示我们可以使用标准库中的对象和变量名称。 如果你

    2024年03月23日
    浏览(46)
  • C#探索之路基础夯实篇(5):语法糖概念解析

    从之前一开始接触lua的时候开始,开始第一次接触到语法糖,后续在看电子书籍的时候屡屡提及到语法糖这个概念,那么语法糖到底是什么呢? 语法糖的概念可以理解为某一段代码的简写或简化形式。它并不是新增功能或语言结构,而是一种更便捷的书写方式,可以使代码更

    2024年04月29日
    浏览(53)
  • Vue3入门指南:零基础小白也能轻松理解的学习笔记

    配置 node.js 15.0 命令行创建命令 npm init vue@latest cd 项目名 npm install npm run dev cnpm下载方法,更快 设置 VSCode 自动保存 官方教程 VSCode + Volar 格式化代码:Shift + Alt + F .vscode:VSCode工具的配置文件 node_modules:Vue项目运行的依赖文件 public:资源文件夹(浏览器图标) src:源码文件

    2024年02月06日
    浏览(44)
  • 深入理解ArkTS:Harmony OS 应用开发语言 TypeScript 的基础语法和关键特性

    Harmony OS应用开发的主力语言ArkTS的前身TS语言的基本语法。通过学习变量的声明和数据类型、条件控制、函数声明、循环迭代等基本知识,并了解内核接口的声明和使用。同时还介绍了模块化开发的概念,提高代码的复用性和开发效率。该对话还涉及了if else和switch条件控制语

    2024年02月04日
    浏览(46)
  • 【React 入门实战篇】从零开始搭建与理解React应用-三、React核心概念与基础语法

    三、React核心概念与基础语法 3.1 JSX语法详解 JSX是React中的一个语法糖,它允许开发者在JavaScript代码中编写类似HTML的标记。这种语法使得开发者能够以一种声明式的方式描述界面,提高了代码的可读性和可维护性。 JSX的语法规则: 元素创建 :使用尖括号 来创建元素,就像在

    2024年04月08日
    浏览(46)
  • 以太坊:轻松理解EIP-4844

    以太坊网络在不断发展,多年来已经提出了许多技术提案。其中一个提案是由Vitalik Buterin提出的EIP-4844,它关注的是分片技术。 什么是EIP-4844,它将如何影响以太坊网络及其用户的未来?以下是对以太坊一项高技术提案的简单易懂的解释,该提案将使网络对所有用户来说都更

    2024年02月02日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包