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

本文主要是介绍C# | 使用AutoResetEvent和ManualResetEvent进行线程同步和通信,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

使用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. 等待所有线程执行完毕。

这篇关于C# | 使用AutoResetEvent和ManualResetEvent进行线程同步和通信的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/457012

相关文章

Go语言使用sync.Mutex实现资源加锁

《Go语言使用sync.Mutex实现资源加锁》数据共享是一把双刃剑,Go语言为我们提供了sync.Mutex,一种最基础也是最常用的加锁方式,用于保证在任意时刻只有一个goroutine能访问共享... 目录一、什么是 Mutex二、为什么需要加锁三、实战案例:并发安全的计数器1. 未加锁示例(存在竞态)

SpringBoot实现虚拟线程的方案

《SpringBoot实现虚拟线程的方案》Java19引入虚拟线程,本文就来介绍一下SpringBoot实现虚拟线程的方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录什么是虚拟线程虚拟线程和普通线程的区别SpringBoot使用虚拟线程配置@Async性能对比H

SpringBoot结合Knife4j进行API分组授权管理配置详解

《SpringBoot结合Knife4j进行API分组授权管理配置详解》在现代的微服务架构中,API文档和授权管理是不可或缺的一部分,本文将介绍如何在SpringBoot应用中集成Knife4j,并进... 目录环境准备配置 Swagger配置 Swagger OpenAPI自定义 Swagger UI 底

C# async await 异步编程实现机制详解

《C#asyncawait异步编程实现机制详解》async/await是C#5.0引入的语法糖,它基于**状态机(StateMachine)**模式实现,将异步方法转换为编译器生成的状态机类,本... 目录一、async/await 异步编程实现机制1.1 核心概念1.2 编译器转换过程1.3 关键组件解析

setsid 命令工作原理和使用案例介绍

《setsid命令工作原理和使用案例介绍》setsid命令在Linux中创建独立会话,使进程脱离终端运行,适用于守护进程和后台任务,通过重定向输出和确保权限,可有效管理长时间运行的进程,本文给大家介... 目录setsid 命令介绍和使用案例基本介绍基本语法主要特点命令参数使用案例1. 在后台运行命令2.

基于Python Playwright进行前端性能测试的脚本实现

《基于PythonPlaywright进行前端性能测试的脚本实现》在当今Web应用开发中,性能优化是提升用户体验的关键因素之一,本文将介绍如何使用Playwright构建一个自动化性能测试工具,希望... 目录引言工具概述整体架构核心实现解析1. 浏览器初始化2. 性能数据收集3. 资源分析4. 关键性能指

使用Redis快速实现共享Session登录的详细步骤

《使用Redis快速实现共享Session登录的详细步骤》在Web开发中,Session通常用于存储用户的会话信息,允许用户在多个页面之间保持登录状态,Redis是一个开源的高性能键值数据库,广泛用于... 目录前言实现原理:步骤:使用Redis实现共享Session登录1. 引入Redis依赖2. 配置R

使用Python的requests库调用API接口的详细步骤

《使用Python的requests库调用API接口的详细步骤》使用Python的requests库调用API接口是开发中最常用的方式之一,它简化了HTTP请求的处理流程,以下是详细步骤和实战示例,涵... 目录一、准备工作:安装 requests 库二、基本调用流程(以 RESTful API 为例)1.

Nginx进行平滑升级的实战指南(不中断服务版本更新)

《Nginx进行平滑升级的实战指南(不中断服务版本更新)》Nginx的平滑升级(也称为热升级)是一种在不停止服务的情况下更新Nginx版本或添加模块的方法,这种升级方式确保了服务的高可用性,避免了因升... 目录一.下载并编译新版Nginx1.下载解压2.编译二.替换可执行文件,并平滑升级1.替换可执行文件

在Java中实现线程之间的数据共享的几种方式总结

《在Java中实现线程之间的数据共享的几种方式总结》在Java中实现线程间数据共享是并发编程的核心需求,但需要谨慎处理同步问题以避免竞态条件,本文通过代码示例给大家介绍了几种主要实现方式及其最佳实践,... 目录1. 共享变量与同步机制2. 轻量级通信机制3. 线程安全容器4. 线程局部变量(ThreadL