C# 中的多线程同步机制:lock、Monitor 和 Mutex 用法详解
在多线程编程中,线程同步是确保多个线程安全地访问共享资源的关键技术。C# 提供了几种常用的同步机制,其中 lock
、Monitor
和 Mutex
是最常用的同步工具。本文将全面介绍这三种同步机制的用法、优缺点以及适用场景,帮助开发者在多线程开发中做出合适的选择。
1. lock
关键字
1.1 概述
在 C# 中,lock
关键字是用于线程同步的最常用工具之一。lock
是 Monitor.Enter()
和 Monitor.Exit()
的语法糖,通过锁住一个共享资源来确保在同一时刻只有一个线程可以访问它。lock
适用于同一个进程中的线程同步,尤其是在多个线程访问共享数据时,能够有效地防止数据竞态和线程安全问题。
1.2 用法
lock
关键字的常见用法是围绕一个对象的引用,将其作为锁对象来同步线程。通常,lock
语句会包装一个临界区(共享资源访问区),当一个线程执行完临界区代码后,另一个线程才能进入临界区。
示例代码:
using System;
using System.Threading;class Program
{private static readonly object _lock = new object(); // 锁对象static void Main(){Thread t1 = new Thread(DoWork);Thread t2 = new Thread(DoWork);t1.Start();t2.Start();}static void DoWork(){lock (_lock) // 获取锁{Console.WriteLine("线程进入临界区...");Thread.Sleep(1000); // 模拟处理时间Console.WriteLine("线程离开临界区...");}}
}
说明:
- 在
lock (_lock)
中,_lock
是锁对象。lock
保证了在同一时刻只有一个线程可以进入lock
语句块内部的代码。 lock
会在代码块执行完毕后自动释放锁,无需手动释放。
1.3 优缺点
优点:
- 语法简洁,易于理解和使用。
- 自动释放锁,减少了因为忘记释放锁而导致死锁的风险。
缺点:
- 只能用于同一个进程中的线程之间的同步,不能跨进程使用。
- 无法提供更多的同步控制,比如等待和通知机制。
2. Monitor
类
2.1 概述
Monitor
类是 C# 提供的底层同步机制,比 lock
更加灵活和精细。Monitor
提供了对锁的手动控制,允许你在获取锁后,等待其他线程的通知或条件满足才能继续执行。Monitor
适合那些需要更多同步控制的场景,比如等待和通知机制。
2.2 用法
Monitor
类提供了几个关键的方法:
Enter(object obj)
:尝试获取锁,如果成功,线程继续执行。Exit(object obj)
:释放锁,允许其他线程访问锁定的资源。Wait(object obj)
:使当前线程等待,直到其他线程通知它。Pulse(object obj)
:唤醒一个等待该锁的线程。PulseAll(object obj)
:唤醒所有等待该锁的线程。
示例代码:
using System;
using System.Threading;class Program
{private static readonly object _lock = new object(); // 锁对象static void Main(){Thread t1 = new Thread(DoWork);Thread t2 = new Thread(DoWork);t1.Start();t2.Start();}static void DoWork(){Monitor.Enter(_lock); // 获取锁try{Console.WriteLine("线程进入临界区...");Thread.Sleep(1000); // 模拟工作Console.WriteLine("线程离开临界区...");}finally{Monitor.Exit(_lock); // 确保释放锁}}
}
说明:
Monitor.Enter(_lock)
获取锁,Monitor.Exit(_lock)
释放锁。Monitor
更加底层,提供了细粒度的控制,适用于复杂的同步场景。- 使用
try
/finally
语句确保即使在发生异常时,也能释放锁。
2.3 优缺点
优点:
- 比
lock
更灵活,支持等待和通知机制,如Wait
、Pulse
和PulseAll
。 - 适用于需要更多控制的同步场景。
缺点:
- 使用起来相对复杂,容易出错,尤其是在手动管理锁时。
- 只支持同一进程内的线程同步。
3. Mutex
类
3.1 概述
Mutex
是 C# 中用于跨进程同步的同步机制。与 lock
和 Monitor
主要用于线程同步不同,Mutex
支持跨进程同步,因此可以用来在不同进程中协调对共享资源的访问。Mutex
的使用相对复杂,但它适用于需要在不同进程间进行同步的场景。
3.2 用法
Mutex
的使用方式与 lock
类似,但它允许在不同的进程间进行同步。Mutex
具有以下关键方法:
WaitOne()
:请求获取互斥锁。ReleaseMutex()
:释放互斥锁,允许其他线程或进程获取锁。
示例代码:
using System;
using System.Threading;class Program
{private static Mutex mutex = new Mutex(); // 创建互斥体static void Main(){Thread t1 = new Thread(DoWork);Thread t2 = new Thread(DoWork);t1.Start();t2.Start();}static void DoWork(){mutex.WaitOne(); // 请求互斥锁Console.WriteLine("线程进入临界区...");Thread.Sleep(1000); // 模拟工作Console.WriteLine("线程离开临界区...");mutex.ReleaseMutex(); // 释放互斥锁}
}
说明:
mutex.WaitOne()
用来请求互斥锁,直到其他线程或进程释放锁。mutex.ReleaseMutex()
用来释放互斥锁,允许其他线程或进程获取锁。
3.3 优缺点
优点:
Mutex
支持跨进程同步,适用于多个进程间的线程同步。- 可以控制同一资源在不同进程间的访问。
缺点:
- 性能开销较大,尤其在涉及跨进程同步时。
- 使用起来较为复杂,需要手动释放锁。
4. lock
、Monitor
和 Mutex
的对比
特性/方法 | lock | Monitor | Mutex |
---|---|---|---|
使用场景 | 线程同步,适用于同一进程内的线程 | 线程同步,提供更多控制(如等待、通知) | 跨进程同步和同一进程内的线程同步 |
性能 | 性能较好,简便易用 | 性能稍差,但提供更多控制 | 性能开销较大,尤其是跨进程同步时 |
跨进程支持 | 不支持 | 不支持 | 支持跨进程同步 |
异常处理 | 自动处理锁的释放 | 需要手动释放锁 | 需要手动释放锁 |
使用复杂度 | 简单易用 | 较复杂,需要手动处理等待和通知 | 较复杂,涉及跨进程操作 |
特点 | 语法简洁 | 更底层,支持等待和通知机制 | 可以跨进程同步 |
适用场景:
lock
:当你只需要简单的线程同步,并且仅在同一个进程内操作时,lock
是最合适的选择。Monitor
:当你需要更多控制,尤其是线程的等待、通知机制时,Monitor
是更好的选择。Mutex
:当你需要跨进程同步时,Mutex
是唯一的选择,它适用于多个进程中的线程同步。
5. 总结
在 C# 中,lock
、Monitor
和 Mutex
是常见的同步机制,它们分别适用于不同的多线程同步需求:
lock
适合简单的线程同步,语法简洁且易于使用。Monitor
提供了更底层的同步控制,适用于复杂的同步需求,如线程的等待、通知等。Mutex
适用于跨进程的同步,尤其在不同进程间共享资源时,Mutex
是必不可少的工具。
根据具体的应用场景,合理选择同步机制能够有效提高程序的性能和稳定性,避免资源竞争和线程安全问题。
相关文章:
C# 中的多线程同步机制:lock、Monitor 和 Mutex 用法详解
在多线程编程中,线程同步是确保多个线程安全地访问共享资源的关键技术。C# 提供了几种常用的同步机制,其中 lock、Monitor 和 Mutex 是最常用的同步工具。本文将全面介绍这三种同步机制的用法、优缺点以及适用场景,帮助开发者在多线程开发中做…...

【通义万相】蓝耘智算 | 开源视频生成新纪元:通义万相2.1模型部署与测评
【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈人工智能与大模型应用 ⌋ ⌋ ⌋ 人工智能(AI)通过算法模拟人类智能,利用机器学习、深度学习等技术驱动医疗、金融等领域的智能化。大模型是千亿参数的深度神经网络(如ChatGPT&…...

期权帮|中证1000股指期权交割结算价怎么算?
期权帮锦鲤三三每日分享期权知识,帮助期权新手及时有效地掌握即市趋势与新资讯! 中证1000股指期权交割结算价怎么算? 一、按照最后交易日结算价: (1)计算方法:最后交易日标的指数(…...
Python 面向对象高级编程-定制类
目录 __str__ __iter__ __getitem__ __getattr__ __call__ 小结 看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的。 __slots__我们已经知道怎么用了,__len__()方法我们也知道是为了能让class作用于len()…...

qt creator示例空白
通常情况下,进入qt后,就会弹出以下窗口: 但如果出现示例空白,那可能是因为 Qt Creator 无法正确识别 Qt 的安装路径或配置。 解决: 点击“添加”: 然后跳转到你的qmake.exe的目录,例如我的qmak…...
MyBatis-Plus 与 Spring Boot 的最佳实践
在现代 Java 开发中,MyBatis-Plus 和 Spring Boot 的结合已经成为了一种非常流行的技术栈。MyBatis-Plus 是 MyBatis 的增强工具,提供了许多便捷的功能,而 Spring Boot 则简化了 Spring 应用的开发流程。本文将探讨如何将 MyBatis-Plus 与 Spring Boot 进行整合,并分享一些…...
TDengine 中的标签索引
简介 本节说明 TDengine 的索引机制。在 TDengine 3.0.3.0 版本之前(不含),默认在第一列 TAG 上建立索引,但不支持给其它列动态添加索引。从 3.0.3.0 版本开始,可以动态地为其它 TAG 列添加索引。对于第一个 TAG 列上…...

工业自动化核心:BM100 信号隔离器的强大力量
安科瑞 吕梦怡 18706162527 BM100系列信号隔离器可以对电流、电压等电量参数或温度、电阻等非电量参数进行快速精确测量,经隔 离转换成标准的模拟信号输出。既可以直接与指针表、数显表相接,也可以与自控仪表(如PLC)、各种 A/D …...

Ascend开发板镜像烧录、联网、其他设备访问
Ascend开发板镜像烧录、联网、外部访问 1.1 Ascend开发板制卡方式一:镜像烧录 SD卡插入读卡器,读卡器插入PC的USB接口 烧录镜像前,先格式化一下SD卡 参考教程:格式化SD卡、修复烧写系统失败的SD卡 WinR,输入cmd DIS…...

Llama-Factory框架下的Meta-Llama-3-8B-Instruct模型微调
目录 引言 Llama - Factory 训练框架简介: Meta - Llama - 3 - 8B - Instruct 模型概述: Lora 方法原理及优势: 原理 优势 环境准备: 部署环境测试: 数据准备: 模型准备: 模型配置与训练࿱…...

MySQL进阶-分析查询语句EXPLAIN
概述 能做什么? 表的读取顺序 数据读取操作的操作类型 哪些索引可以使用 哪些索引被实际使用 表之间的引用 每张表有多少行被优化器查询 官网介绍 https://dev.mysql.com/doc/refman/5.7/en/explain-output.html https://dev.mysql.com/doc/refman/8.0/…...
Python 高级编程与实战:构建数据可视化应用
在前几篇文章中,我们探讨了 Python 的基础语法、面向对象编程、函数式编程、元编程、性能优化、调试技巧、数据科学、机器学习、Web 开发、API 设计、网络编程、异步IO、并发编程、设计模式与软件架构、性能优化与调试技巧、分布式系统、微服务架构、自动化测试框架以及 RESTf…...

学习threejs,Animation、Core、CustomBlendingEquation、Renderer常量汇总
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️Animation常量汇总1.1.1 循…...
Java直通车系列14【Spring MVC】(深入学习 Controller 编写)
目录 基本概念 编写 Controller 的步骤和要点 1. 定义 Controller 类 2. 映射请求 3. 处理请求参数 4. 调用业务逻辑 5. 返回响应 场景示例 1. 简单的 Hello World 示例 2. 处理路径变量和请求参数 3. 处理表单提交 4. 处理 JSON 数据 5. 异常处理 基本概念 Cont…...
【蓝桥杯集训·每日一题2025】 AcWing 5539. 牛奶交换 python
AcWing 5539. 牛奶交换 Week 3 3月6日 题目描述 农夫约翰的 N N N 头奶牛排成一圈,使得对于 1 , 2 , … , N − 1 1,2,…,N−1 1,2,…,N−1 中的每个 i i i,奶牛 i i i 右边的奶牛是奶牛 i 1 i1 i1,而奶牛 N N N 右边的奶牛是奶牛 …...

Mybatis缓存机制(一级缓存和二级缓存)
前言 为什么要学习Mybatis 缓存机制? 学习Mybatis 缓存机制,可以有效解决 数据库的压力,提高数据库的性能。 例如:你要 对tb_user 表 ,查询 所有用户的信息,并且多次查询所有用户信息。我们知道第一次查询表信息流…...
设计模式--单例模式
一、单例模式代码实现 public class DatabaseConnection {// 1. 私有静态实例变量private static DatabaseConnection instance;// 2. 私有构造函数,防止外部直接创建实例private DatabaseConnection() {// 初始化数据库连接System.out.println("Database con…...

ubuntu22.04本地部署OpenWebUI
一、简介 Open WebUI 是一个可扩展、功能丰富且用户友好的自托管 AI 平台,旨在完全离线运行。它支持各种 LLM 运行器,如 Ollama 和 OpenAI 兼容的 API,并内置了 RAG 推理引擎,使其成为强大的 AI 部署解决方案。 二、安装 方法 …...

2025-3-7二叉树的线索化
一、中序线索化 代码其实就是和中序遍历相似,增加了两个标志位 ltag rtag。 完整的代码: 二、先序线索化: 三、后序线索化: 总结:其核心其实还是遍历算法的改造。 并且注意处理最后一个被访问的节点。...

以商业思维框架为帆,驭创业浪潮前行
创业者踏入商海,如同航海家奔赴未知海域,需有清晰的思维罗盘指引方向。图中“为什么—用什么—怎么做—何人做—投入产出”的商业框架,正是创业者破解商业谜题的密钥,从需求洞察到落地执行,为创业之路铺就逻辑基石。 …...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...

微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...

UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...