聊透多线程编程-线程互斥与同步-13. C# Mutex类实现线程互斥

目录

一、什么是临界区?

二、Mutex类简介

三、Mutex的基本用法

解释:

四、Mutex的工作原理

五、使用示例1-保护共享资源

解释:

六、使用示例2-跨进程同步

示例场景

1. 进程A - 主进程

2. 进程B - 第二个进程

输出结果

ProcessA 的输出

ProcessB 的输出

解释

七、注意事项

八、总结


 

在多线程编程中,线程之间的同步和互斥是确保程序正确运行的重要机制。C# 提供了多种工具来实现线程同步,其中 Mutex 是一种功能强大的同步原语,特别适合用于跨进程的线程互斥场景。本文将详细介绍如何使用 Mutex 类实现线程互斥,并通过示例展示其工作原理。


一、什么是临界区?

在多线程编程中,临界区是指一段需要互斥访问的代码块,通常涉及对共享资源的操作。为了避免多个线程同时操作共享资源而导致数据竞争或状态不一致,我们需要对临界区代码进行保护。

例如,如果两个线程同时修改一个共享变量,可能会导致最终结果不符合预期。因此,我们需要一种机制来确保同一时间只有一个线程可以进入临界区。


二、Mutex类简介

Mutex(Mutual Exclusion)类是 .NET 提供的一种线程同步工具,用于实现线程间的互斥访问。与 lockMonitor 不同,Mutex 支持跨进程的线程同步,这使得它非常适合用于多进程环境下的资源保护。

Mutex 的主要特点包括:

  • 跨进程支持Mutex 可以在不同进程之间共享,适用于分布式或多进程应用。
  • 独占锁:同一时间只有一个线程(或进程)可以持有 Mutex
  • 命名支持:可以通过命名方式创建全局 Mutex,从而实现跨进程同步。

三、Mutex的基本用法

Mutex 的基本用法包括以下几个步骤:

  1. 创建 Mutex 对象。
  2. 调用 WaitOne 方法获取锁。
  3. 执行需要同步的代码块。
  4. 调用 ReleaseMutex 方法释放锁。

为了确保资源的正确释放,通常会将 Mutex 放入 using 块中,这样即使发生异常,也能保证资源被正确释放。

using System;
using System.Threading;class Program
{private static readonly Mutex _mutex = new Mutex(); // 创建 Mutex 对象static void Main(){Thread t1 = new Thread(DoWork);Thread t2 = new Thread(DoWork);t1.Start();t2.Start();t1.Join();t2.Join();}static void DoWork(){Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}: Waiting for mutex...");_mutex.WaitOne(); // 获取锁try{Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}: Entered critical section.");Thread.Sleep(2000); // 模拟一些工作}finally{_mutex.ReleaseMutex(); // 释放锁Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}: Released mutex.");}}
}

解释:

  • _mutex.WaitOne():尝试获取锁。如果锁已被占用,则当前线程会被阻塞,直到锁可用。
  • _mutex.ReleaseMutex():释放锁,允许其他线程获取该锁。
  • 使用 try-finally 块是为了确保即使发生异常,锁也能被正确释放。

四、Mutex的工作原理

Mutex 的核心思想是基于操作系统级别的信号量机制,提供了更高级别的同步能力:

  1. 当线程调用 WaitOne 方法时,它会尝试获取 Mutex。如果 Mutex 已被其他线程占用,则当前线程会被挂起,直到 Mutex 可用。
  2. 当线程调用 ReleaseMutex 方法时,它会释放 Mutex,允许其他线程获取该锁。
  3. 如果 Mutex 是命名的(通过构造函数指定名称),它可以跨进程共享,从而实现跨进程同步。

五、使用示例1-保护共享资源

下面是一个使用 Mutex 类保护共享资源的例子:

using System;
using System.Threading;class Program
{private static int _counter = 0;private static readonly Mutex _mutex = new Mutex();static void Main(){Thread t1 = new Thread(IncrementCounter);Thread t2 = new Thread(IncrementCounter);t1.Start();t2.Start();t1.Join();t2.Join();_mutex.Dispose();Console.WriteLine($"Final Counter Value: {_counter}");}static void IncrementCounter(){for (int i = 0; i < 100000; i++){_mutex.WaitOne();try{_counter++;}finally{_mutex.ReleaseMutex();}}}
}

解释:

  • _mutex 是一个静态对象,用于标识锁。
  • 每次访问 _counter 时,都会通过 WaitOne 获取锁,并通过 ReleaseMutex 释放锁。
  • 最终输出的结果是 200000,因为所有线程的操作都被正确同步了。

六、使用示例2-跨进程同步

Mutex 的跨进程同步能力使其非常适合用于分布式或多进程环境中的资源共享和互斥访问。下面通过一个完整的例子,演示如何使用命名的 Mutex 来实现跨进程同步。

示例场景

假设我们有两个独立的应用程序(进程),它们都需要访问一个共享资源(例如文件或数据库)。为了避免数据竞争,我们需要确保同一时间只有一个进程可以访问该资源。我们将使用命名的 Mutex 来实现这一目标。

1. 进程A - 主进程

这是第一个应用程序,它尝试获取 Mutex 并独占访问共享资源。

// ProcessA.cs
using System;
using System.Threading;class Program
{static void Main(string[] args){// 创建一个命名的 Mutexbool isCreatedNew; // 是否是第一个创建 Mutex 的进程using (Mutex mutex = new Mutex(true, "Global\\SharedResourceMutex", out isCreatedNew)){if (isCreatedNew){Console.WriteLine("Process A: This process owns the mutex.");Console.WriteLine("Process A: Accessing shared resource...");// 模拟对共享资源的操作Thread.Sleep(50000); // 假设操作需要 5 秒                Console.WriteLine("Process A: Releasing mutex.");//释放锁mutex.ReleaseMutex();}else{Console.WriteLine("Process A: Another process already owns the mutex. Waiting...");// 等待其他进程释放 Mutexmutex.WaitOne();Console.WriteLine("Process A: Acquired mutex after waiting.");// 模拟对共享资源的操作Console.WriteLine("Process A: Accessing shared resource...");Thread.Sleep(5000);Console.WriteLine("Process A: Releasing mutex.");//释放锁mutex.ReleaseMutex();}}}
}

2. 进程B - 第二个进程

这是第二个应用程序,它也会尝试获取同一个 Mutex,并访问共享资源。

// ProcessB.cs
using System;
using System.Threading;class Program
{static void Main(string[] args){// 创建一个命名的 Mutexbool isCreatedNew; // 是否是第一个创建 Mutex 的进程using (Mutex mutex = new Mutex(true, "Global\\SharedResourceMutex", out isCreatedNew)){try{if (isCreatedNew){Console.WriteLine("Process B: This process owns the mutex.");Console.WriteLine("Process B: Accessing shared resource...");// 模拟对共享资源的操作Thread.Sleep(5000); // 假设操作需要 5 秒Console.WriteLine("Process B: Releasing mutex.");//释放锁mutex.ReleaseMutex();}else{Console.WriteLine("Process B: Another process already owns the mutex. Waiting...");// 等待其他进程释放 Mutexmutex.WaitOne();Console.WriteLine("Process B: Acquired mutex after waiting.");// 模拟对共享资源的操作Console.WriteLine("Process B: Accessing shared resource...");Thread.Sleep(5000);Console.WriteLine("Process B: Releasing mutex.");//释放锁mutex.ReleaseMutex();}}catch (AbandonedMutexException){Console.WriteLine("Process B: Detected an abandoned mutex. Continuing execution...");// 即使检测到被遗弃的 Mutex,当前线程仍然可以继续执行。}}}
}

输出结果

ProcessA 的输出

Process A: This process owns the mutex.
Process A: Accessing shared resource...
Process A: Releasing mutex.

ProcessB 的输出

Process B: Another process already owns the mutex. Waiting...
Process B: Acquired mutex after waiting.
Process B: Accessing shared resource...
Process B: Releasing mutex.

解释

  1. 命名的 Mutex

    • 在 new Mutex(true, "Global\\SharedResourceMutex", out isCreatedNew) 中,"Global\\SharedResourceMutex" 是 Mutex 的名称。
    • Global\\ 前缀表示该 Mutex 是全局的,可以在不同进程之间共享。
  2. 跨进程同步

    • 当 ProcessA 创建 Mutex 时,isCreatedNew 为 true,表示它是第一个创建该 Mutex 的进程。
    • 当 ProcessB 尝试创建同名的 Mutex 时,isCreatedNew 为 false,表示该 Mutex 已存在,并由另一个进程持有。
  3. 等待与释放

    • 如果 Mutex 已被占用,调用 mutex.WaitOne() 会使当前线程阻塞,直到 Mutex 被释放。
    • 调用 mutex.ReleaseMutex() 会释放 Mutex,允许其他线程或进程获取它。

七、注意事项

  1. 命名冲突

    • 命名的 Mutex 必须具有唯一性,避免与其他应用程序发生冲突。
    • 可以使用 GUID 或特定的前缀来确保名称的唯一性。
  2. 性能开销

    • Mutex 是基于操作系统级别的同步机制,性能开销较大,尤其是在高并发场景下。
    • 对于单进程内的线程同步,推荐使用 lock 或 Monitor
  3. 死锁风险

    • 如果一个进程获取了 Mutex 但未释放,会导致其他进程永远无法获取锁。
    • 确保在 finally 块中调用 ReleaseMutex,避免因异常导致锁未释放。
  4. 权限问题

    • 在某些情况下,创建全局 Mutex 可能需要管理员权限,尤其是在 Windows 系统中。
  5. 为什么使用 using

    • 将 Mutex 放入 using 块中可以确保资源的正确释放,避免资源泄漏。
    • 即使发生异常,Dispose 方法也会被自动调用,保证资源管理的安全性和可靠性。

八、总结

Mutex 类是 C# 中实现线程互斥的一种重要工具,特别适合用于跨进程的线程同步场景。尽管它的使用稍微复杂一些,但能够满足更多高级需求,例如分布式系统中的资源保护。

在实际开发中,选择合适的同步机制非常重要。对于简单的线程互斥场景,lockMonitor 可能更为直观;而对于需要跨进程同步的场景,Mutex 则是一个不错的选择。通过合理利用 Mutex,我们可以有效避免数据竞争和资源冲突,确保多线程或多进程应用的稳定性和可靠性。

 

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

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

相关文章

stm32week12

stm32学习 九.stm32与HAL库 2.HAL库框架 总架构&#xff1a; 文件介绍&#xff1a; ppp是某一外设&#xff0c;ex是拓展功能 HAL库API函数和变量命名规则&#xff1a; HAL库对寄存器位操作的相关宏定义&#xff1a; HAL库的回调函数&#xff1a; 3.STM32启动过程 MDK编译过…

opencv HSV的具体描述

色调H&#xff1a; 使用角度度量&#xff0c;取值范围为0\~360&#xff0c;从红色开始按逆时针方向计算&#xff0c;红色为0&#xff0c;绿色为120&#xff0c;蓝色为240。它们的补色是&#xff1a;黄色为60&#xff0c;青色为180&#xff0c;紫色为300。通过改变H的值&#x…

Java Lambda表达式指南

一、Lambda表达式基础 1. 什么是Lambda表达式&#xff1f; 匿名函数&#xff1a;没有名称的函数函数式编程&#xff1a;可作为参数传递的代码块简洁语法&#xff1a;替代匿名内部类的更紧凑写法 2. 基本语法 (parameters) -> expression 或 (parameters) -> { statem…

面向对象设计中的类的分类:实体类、控制类和边界类

目录 前言1. 实体类&#xff08;Entity Class&#xff09;1.1 定义和作用1.2 实体类的特点1.3 实体类的示例 2. 控制类&#xff08;Control Class&#xff09;2.1 定义和作用2.2 控制类的特点2.3 控制类的示例 3. 边界类&#xff08;Boundary Class&#xff09;3.1 定义和作用3…

C# 封装教程

原文&#xff1a;C# 封装_w3cschool &#xff08;注&#xff1a;本文为教程文章&#xff0c;请勿标记为付费文章&#xff01;特此声明&#xff09; 封装 被定义为"把一个或多个项目封闭在一个物理的或者逻辑的包中"。在面向对象程序设计方法论中&#xff0c;封装是…

量化交易 - RSRS(阻力支撑相对强度)- 正确用法 - 年均收益18%

经过研究&#xff0c;发现RSRS的正确用法其实是需要用到两个数据&#xff0c;分别是 n: 一阶拟合样本数&#xff0c;m:求均值方差样本数&#xff0c;其中n比较小 如18&#xff0c;m比较大 如1100 经过调优后&#xff0c;收益率显著上升&#xff01; 如下图&#xff1a; &…

Oracle expdp的 EXCLUDE 参数详解

Oracle expdp的 EXCLUDE 参数详解 EXCLUDE 是 Oracle Data Pump Export (expdp) 工具中的一个关键参数&#xff0c;用于指定在导出过程中要排除的对象或对象类型。 一、基本语法 expdp username/password DUMPFILEexport.dmp DIRECTORYdpump_dir EXCLUDEobject_type[:name_c…

如何使用3DMAX插件PFSpliner将3D对象转化为艺术样条线?

什么是粒子流源(Particle Flow)是3DMAX的一个功能极其强大的粒子系统。它采用事件驱动模型,使用一个名为“粒子视图”的特殊对话框。在“粒子视图”中,您可以将描述粒子属性(如形状、速度、方向和一段时间内的旋转)的单个运算符组合成称为事件的组。每个操作符都提供一组…

【python】 循环语句(while)

1、循环语句 语法&#xff1a; while 条件:......... #只有条件为真时&#xff0c;才会执行while中的内容。 1.1循环语句基本使用 示例1&#xff1a; print("开始") while 1>2:print("人生得意须尽欢") print("结束") #输出结果&#…

OOA-CNN-LSTM-Attention、CNN-LSTM-Attention、OOA-CNN-LSTM、CNN-LSTM四模型多变量时序预测一键对比

OOA-CNN-LSTM-Attention、CNN-LSTM-Attention、OOA-CNN-LSTM、CNN-LSTM四模型多变量时序预测一键对比 目录 OOA-CNN-LSTM-Attention、CNN-LSTM-Attention、OOA-CNN-LSTM、CNN-LSTM四模型多变量时序预测一键对比预测效果基本介绍程序设计参考资料 预测效果 基本介绍 基于OOA-CN…

20250421在荣品的PRO-RK3566开发板的Android13下频繁重启RKNPU fde40000.npu: Adding to iommu gr

20250421在荣品的PRO-RK3566开发板的Android13下频繁重启RKNPU fde40000.npu: Adding to iommu gr 2025/4/21 14:50 缘起&#xff1a;电池没电了&#xff0c;导致荣品的PRO-RK3566的核心板频繁重启。 内核时间4s就重启。100%复现。 PRO-RK3566 Android13启动到这里 复位&#…

动态监控进程

1.介绍: top和ps命令很相似,它们都是用来显示正在执行的进程,top和ps最大的不同之处,在于top在执行中可以更新正在执行的进程. 2.基本语法&#xff1a; top [选项] 选项说明 ⭐️僵死进程&#xff1a;内存没有释放,但是进程已经停止工作了,需要及时清理 交互操作说明 应用案…

657SJBH西藏藏药特产销售管理系统

毕业论文&#xff08;设计&#xff09;文献综述 西藏藏药特产销售管理系统的设计与实现 近年来&#xff0c;随着网络技术特别是Internet技术的普及和发展&#xff0c;电子商务的开发和应用成为一个热门领域&#xff0c;在线藏药特产销售系统就是这其中的一员。 藏药产业在西藏…

栈和队列--数据结构初阶(2)(C/C++)

文章目录 前言理论部分栈的模拟实现STL中的栈容器队列的模拟实现STL中的队列容器 作业部分 前言 这期的话会给大家讲解栈和队列的模拟实现和在STL中栈和队列怎么用的一些知识和习题部分(这部分侧重于理论知识&#xff0c;习题倒还是不难) 理论部分 栈的模拟实现 typedef int…

RNN的理解

对于RNN的理解 import torch import torch.nn as nn import torch.nn.functional as F# 手动实现一个简单的RNN class RNN(nn.Module):def __init__(self, input_size, hidden_size, output_size):super(RNN, self).__init__()# 定义权重矩阵和偏置项self.hidden_size hidden…

二叉查找树和B树

二叉查找树&#xff08;Binary Search Tree, BST&#xff09;和 B 树&#xff08;B-tree&#xff09;都是用于组织和管理数据的数据结构&#xff0c;但它们在结构、应用场景和性能方面有显著区别。 二叉查找树&#xff08;Binary Search Tree, BST&#xff09; 特点&#xff1…

一段式端到端自动驾驶:VAD:Vectorized Scene Representation for Efficient Autonomous Driving

论文地址&#xff1a;https://github.com/hustvl/VAD 代码地址&#xff1a;https://arxiv.org/pdf/2303.12077 1. 摘要 自动驾驶需要对周围环境进行全面理解&#xff0c;以实现可靠的轨迹规划。以往的方法依赖于密集的栅格化场景表示&#xff08;如&#xff1a;占据图、语义…

OpenCV训练题

一、创建一个 PyQt 应用程序&#xff0c;该应用程序能够&#xff1a; 使用 OpenCV 加载一张图像。在 PyQt 的窗口中显示这张图像。提供四个按钮&#xff08;QPushButton&#xff09;&#xff1a; 一个用于将图像转换为灰度图一个用于将图像恢复为原始彩色图一个用于将图像进行…

opencv函数展示4

一、形态学操作函数 1.基本形态学操作 &#xff08;1&#xff09;cv2.getStructuringElement() &#xff08;2&#xff09;cv2.erode() &#xff08;3&#xff09;cv2.dilate() 2.高级形态学操作 &#xff08;1&#xff09;cv2.morphologyEx() 二、直方图处理函数 1.直方图…

iPhone 13P 换超容电池,一年实记的“电池循环次数-容量“柱状图

继上一篇 iPhone 13P 更换"移植电芯"和"超容电池"&#x1f50b;体验&#xff0c;详细记录了如何更换这两种电池&#xff0c;以及各自的优略势对比。 一晃一年过去&#xff0c;时间真快&#xff0c;这次分享下记录了使用超容电池的 “循环次数 - 容量(mAh)…