C# | 使用AutoResetEvent和ManualResetEvent进行线程同步和通信

news2024/9/28 3:26:30

在这里插入图片描述

使用AutoResetEvent和ManualResetEvent进行线程同步和通信

文章目录

  • 使用AutoResetEvent和ManualResetEvent进行线程同步和通信
    • 介绍
      • AutoResetEvent
      • ManualResetEvent
    • 异同点
    • 使用场景和代码示例
      • AutoResetEvent 使用示例
      • ManualResetEvent 使用示例
      • 阻塞多个线程并同时激活

介绍

在多线程编程中,AutoResetEvent 和 ManualResetEvent 是两个常用的同步原语。它们用于线程间的通信和协调,以确保线程按照特定的顺序执行。本篇博客将介绍这两种同步原语的概念、用法和区别。

AutoResetEvent

AutoResetEvent (自动重置事件)是一个同步基元,它允许一个线程等待其他线程在信号状态之前进行等待,用于在线程间提供简单的信号通知机制。它的工作方式是,当一个线程通过调用 WaitOne() 方法等待事件信号时,如果事件处于非终止状态,线程将被阻塞。当另一个线程调用 Set() 方法将事件设置为终止状态时,等待的线程将被唤醒,并且事件将自动重置为非终止状态。

ManualResetEvent

ManualResetEvent (手动重置事件)也是一个同步基元,它与AutoResetEvent类似,也用于在线程间提供信号通知机制。与 AutoResetEvent 不同的是,ManualResetEvent 在设置为终止状态后,会一直保持终止状态,直到调用 Reset() 方法将其重置为非终止状态。另外,它允许所有等待的线程在同一个信号状态下被唤醒。当一个线程通过调用 WaitOne() 方法等待事件信号时,如果事件处于非终止状态,线程将被阻塞。只有当事件被设置为终止状态时,线程才会被唤醒。

异同点

虽然 AutoResetEvent 和 ManualResetEvent 都用于线程间的同步和通信,它们之间有以下几个关键的异同点:

  • 重置行为:AutoResetEvent 在一个等待线程被唤醒后会自动将事件重置为非终止状态,而 ManualResetEvent 则需要显式地调用 Reset() 方法将事件重置为非终止状态。
  • 信号通知:AutoResetEvent 只允许一个等待线程被唤醒,即使有多个线程等待;而 ManualResetEvent 允许多个等待线程被唤醒。
  • 等待过程:AutoResetEvent 在一个等待线程被唤醒后,其他等待线程仍然会继续等待;而 ManualResetEvent 在一个等待线程被唤醒后,所有等待线程都会被唤醒。

使用场景和代码示例

根据上述的异同点,我们可以根据不同的需求来选择使用 AutoResetEvent 或 ManualResetEvent。

AutoResetEvent 使用示例

我们创建了两个工作线程,并使用 AutoResetEvent 来同步它们的执行。在主线程中,我们先唤醒第一个等待线程,然后等待一段时间再唤醒第二个等待线程。这样,每个线程只会被唤醒一次,然后自动重置事件,继续等待下一个信号。

  using System;
  using System.Threading;

  class Program
  {
      static AutoResetEvent autoResetEvent = new AutoResetEvent(false);

      static void Main(string[] args)
      {
          Thread thread1 = new Thread(Worker);
          Thread thread2 = new Thread(Worker);

          thread1.Start();
          thread2.Start();

          // 唤醒第一个等待线程
          autoResetEvent.Set();

          // 唤醒第二个等待线程
          Thread.Sleep(1000);
          autoResetEvent.Set();

          // 等待线程执行完毕
          thread1.Join();
          thread2.Join();
      }

      static void Worker()
      {
          Console.WriteLine("Worker started");
          autoResetEvent.WaitOne();
          Console.WriteLine("Worker finished");
      }
  }

ManualResetEvent 使用示例

我们同样创建了两个工作线程,但这次使用ManualResetEvent 来同步它们的执行。在主线程中,我们设置了事件为终止状态,这将唤醒所有等待线程。由于 ManualResetEvent 保持终止状态,每个线程只会被唤醒一次,然后继续执行直到结束。

  using System;
  using System.Threading;

  class Program
  {
      static ManualResetEvent manualResetEvent = newManualResetEvent(true);

      static void Main(string[] args)
      {
          Thread thread1 = new Thread(Worker);
          Thread thread2 = new Thread(Worker);

          thread1.Start();
          thread2.Start();

          // 唤醒所有等待线程
          manualResetEvent.Set();

          // 等待线程执行完毕
          thread1.Join();
          thread2.Join();
      }

      static void Worker()
      {
          Console.WriteLine("Worker started");
          manualResetEvent.WaitOne();
          Console.WriteLine("Worker finished");
      }
  }

阻塞多个线程并同时激活

如果需要阻塞多个线程并同时激活多个线程,建议使用 ManualResetEvent。原因是 ManualResetEvent 允许多个等待线程被唤醒,而 AutoResetEvent 只允许一个等待线程被唤醒。

下面是一个使用 ManualResetEvent 的示例代码:

using System;
using System.Threading;

class Program
{
    static ManualResetEvent manualResetEvent = new ManualResetEvent(false);

    static void Main(string[] args)
    {
        Thread[] threads = new Thread[5];

        for (int i = 0; i < threads.Length; i++)
        {
            threads[i] = new Thread(Worker);
            threads[i].Start();
        }

        // 阻塞所有线程
        Console.WriteLine("Blocking all threads...");
        manualResetEvent.WaitOne();

        // 激活所有线程
        Console.WriteLine("Activating all threads...");
        manualResetEvent.Set();

        // 等待线程执行完毕
        foreach (Thread thread in threads)
        {
            thread.Join();
        }
    }

    static void Worker()
    {
        Console.WriteLine("Worker started");
        manualResetEvent.WaitOne();
        Console.WriteLine("Worker finished");
    }
}

在示例中创建了 5 个工作线程,并使用 ManualResetEvent 来阻塞和激活这些线程。执行的流程为:

  1. 主线程将 ManualResetEvent 设置为非终止状态,阻塞所有的工作线程;
  2. 主线程打印消息并将 ManualResetEvent 设置为终止状态,激活所有的工作线程;
  3. 等待所有线程执行完毕。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1284256.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【无标题】广东便携式逆变器的澳洲安全 AS/NZS 4763

便携式逆变器的澳洲安全 AS/NZS 4763 便携式逆变器申请澳大利亚和新西兰SAA认证的时候&#xff0c;需要按照澳洲*用标准AS/NZS 4763: 2011进行测试。立讯检测安规实验室有澳洲AS/NZS 4763: 2011资质授权&#xff0c;为国内多家便携式逆变器客户成功申请澳洲SAA证书 便携式户外…

EXCEL中如何替换TRUE和FALSE

问题&#xff1a; 在EXCEL中使用查找/替换时&#xff0c;发现TRUE和FALSE不能被替换成true和false&#xff0c;替换了多次&#xff0c;一点反应都没有。网上提供的方法均是使用公式的大小写转换&#xff0c;但这个显然太麻烦了。通过摸索&#xff0c;找到了一种替换方法。 解…

力扣7.整数反转

题目描述 代码 自己写的像屎山&#xff0c;虽然能通过&#xff0c;但多了很多不必要的代码。 class Solution {public int reverse(int x) {int count 0;int res 0;//用temp2记录x的正负int temp2 x;if(x < 0){x -x;}int temp x;while(temp ! 0){temp temp / 10;cou…

36.位运算符

一.什么是位运算符 按照二进制位来进行运算的运算符叫做位运算符&#xff0c;所以要先将操作数转换成二进制&#xff08;补码&#xff09;的形式在运算。C语言的中的位运算符有&#xff1a; 运算符作用举例结果& 按位与&#xff08;and&#xff09; 0&00; 0&10; …

老化房设备材料选型要素

一&#xff1a;选择高温老化试验设备时&#xff0c;需要考虑以下几个因素&#xff1a; 温度范围&#xff1a;根据待测材料或产品的使用环境和需求&#xff0c;选择合适的温度范围。确保试验设备的最高和最低温度能够满足需求。控温精度&#xff1a;控温精度越高&#xff0c;试…

【Java基础】几种拼接字符串的方法

几种拼接字符串的方法 1.使用 "" 运算符拼接字符串2.使用 StringBuilder 或 StringBuffer 类3.使用 StringJoiner 类4.使用 String 类 join 方法5.使用 StringUtils 类6.使用 String 类 concat 方法7.使用 String.format() 方法格式化字符串8.使用 Stream 实现9.总结…

Python字符串模糊匹配工具:TheFuzz 库详解

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在处理文本数据时&#xff0c;常常需要进行模糊字符串匹配来找到相似的字符串。Python的 TheFuzz 库提供了强大的方法用于解决这类问题。本文将深入介绍 TheFuzz 库&#xff0c;探讨其基本概念、常用方法和示例代…

ES6 import

这里 import 的文件是项目内自己 export 的对象&#xff0c;并非 package.json 里引用的包。 后者的打包策略和配置有关。 原理&#xff1a;彻底理解JavaScript ES6中的import和export - 知乎

Db2的Activity event monitor在Db2 MPP V2上收集ROWS_INSERTED信息

注&#xff1a;本文不是讲解Db2 Activity event monitor&#xff0c;只是一个用法实践。要了解Activity event monitor&#xff0c;请参考 https://www.ibm.com/docs/en/db2/11.5?topicevents-activity-event-monitoring 。 环境 Red Hat Enterprise Linux release 8.8 (Oot…

手把手教你搭建个人地图服务器(高德离线部署解决方案):获取地图瓦片数据、高德JS API、私有化部署和调用。。。

一、概述 众所周知&#xff0c;目前常见的地图&#xff08;高德、百度、腾讯等&#xff09;只提供在线API服务&#xff0c;对于一些内网应用而言&#xff0c;如果需要使用地图展示&#xff0c;则由于不能访问互联网而无法使用类似的第三方地图服务。 本文&#xff0c;通过将高…

【web安全】RCE漏洞原理

前言 菜某的笔记总结&#xff0c;如有错误请指正。 RCE漏洞介绍 简而言之&#xff0c;就是代码中使用了可以把字符串当做代码执行的函数&#xff0c;但是又没有对用户的输入内容做到充分的过滤&#xff0c;导致可以被远程执行一些命令。 RCE漏洞的分类 RCE漏洞分为代码执行…

【C语言】递归详解

目录 1.前言2. 递归的定义3. 递归的限制条件4. 递归举例4.1 求n的阶乘4.1.1 分析和代码实现4.1.2 画图演示 4.2 顺序打印一个整数的每一位4.2.1 分析和代码实现4.2.2 画图推演 4.3 求第n个斐波那契数 5. 递归与迭代5.1 迭代求第n个斐波那契数 1.前言 这次博客内容是与递归有关&…

日期类 - Java

知道怎么查&#xff0c;怎么用即可&#xff0c;不用每个方法都背 日期类 第一代日期类方法演示 第二代日期类方法演示 第三代日期类前面两代日期类的不足分析第三代日期类常见方法方法演示 第一代日期类 Date类&#xff1a;精确到毫秒&#xff0c;代表特定的瞬间SimpleDateFor…

51单片机开发——day01

1、软件安装&#xff1a; 2、单片机&#xff08;Micro Controller Unit&#xff09;MCU: 内部集成了cpu&#xff0c;RAM&#xff0c;ROM&#xff0c;定时器&#xff0c;中断系统&#xff0c;通讯接口&#xff0c; 用于信息采集处理硬件设备控制&#xff1b; 8051内核所以带了这…

手把手教你做基于stm32的红外、语音、按键智能灯光控制(上)

目录&#xff1a; 1.系统实现目标2.硬件选型和软件准备2.1. 硬件选型2.2 软件准备 3. 硬件IO表4.各个模块的驱动函数4.1. 红外遥控模块4.2. 按键模块4.3. LED灯4.4. BH1750光照度传感器4.5. 红外检测模块 1.系统实现目标 本文所设计的基于单片机的灯光控制系统主要由模式选择功…

【C++】树型结构关联式容器:map/multimap/set/multisetの使用指南(27)

前言 大家好吖&#xff0c;欢迎来到 YY 滴C系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 目录 一.键值对二.关联式容器&#xff06;序列…

国产API调试插件:Apipost-Helper

前言 Idea 是一款功能强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;它可以帮助开发人员更加高效地编写、调试和部署软件应用程序,Idea 还具有许多插件和扩展&#xff0c;可以根据开发人员的需要进行定制和扩展&#xff0c;从而提高开发效率,今天我们就来介绍一款…

uniapp-距离distance数字太长,截取保留前3为数字

1.需求 将接口返回的距离的字段&#xff0c;保留三位数显示。 2.实现效果 3.代码&#xff1a; 1.这是接口返回的数据&#xff1a; 2.调取接口&#xff0c;赋值前先处理每条数据的distance <view class"left">距你{{item.distance}}km</view>listFun() …

C语言面试之旅:掌握基础,探索深度(面试实战之ARM架构一)

从前不会回头&#xff0c;往后不会将就。 ----小新 一.ARM采用32位架构 ARM约定一个Byte是8 bits&#xff0c;一个Halfword是16 bits (2 byte)&#xff0c;一个Word是32 bits (4 byte)。大部分ARM core …

回溯法及例题(C++实现)

回溯法概念 概念&#xff1a;在包含问题所有解的解空间树中&#xff0c;按照深度优先搜索的策略&#xff0c;根据根结点&#xff08;开始节点&#xff09;出发搜索解空间树。 流程&#xff1a;首先根结点成为活节点&#xff0c;同时也成为当前的扩展结点。在当前的扩展结点处…