0

0

c# Mutex 和 SemaphoreSlim 的区别和选择

月夜之吻

月夜之吻

发布时间:2026-01-01 09:50:03

|

995人浏览过

|

来源于php中文网

原创

该用 Mutex 而非 SemaphoreSlim 的唯一场景是跨进程同步,如单实例限制或多个独立进程协调共享资源;SemaphoreSlim 仅限进程内高并发、短临界区及异步场景,性能远超 Mutex。

c# mutex 和 semaphoreslim 的区别和选择

什么时候该用 Mutex,而不是 SemaphoreSlim

只在需要跨进程同步时才选 Mutex——比如确保整个操作系统里只有一个程序实例运行,或多个独立进程(如 Windows 服务 + 桌面客户端)要协调访问同一份文件或共享内存。SemaphoreSlim 完全不能跨进程,它连操作系统句柄都不创建,纯用户态实现。

  • ✅ 正确场景:Mutex 用于单实例限制(命名互斥体)、进程间资源仲裁
  • ❌ 错误场景:仅在同一个进程内做线程同步,却用 Mutex——性能差 50 倍以上,且容易因未释放导致死锁
  • ⚠️ 注意:Mutex 必须由持有它的线程调用 ReleaseMutex(),否则其他线程永远等不到;而 SemaphoreSlim 任意线程都能调用 Release()

SemaphoreSlim 的真实优势在哪

它不是“简化版信号量”,而是为高并发、短临界区和异步编程专门优化的同步基元。它在无竞争时完全不进内核,靠自旋+轻量队列处理;一旦有争抢,才可能升级到内核等待——这比 SemaphoreMutex 每次都触发系统调用快得多。

  • ✅ 推荐场景:限制线程池并发数(如 Parallel.ForEachAsync 控制最大并发 HTTP 请求)、生产者-消费者缓冲区计数、API 限流中间件
  • ✅ 异步友好:WaitAsync() 不阻塞线程,适合 ASP.NET Core 等 I/O 密集型服务
  • ❌ 不支持跨进程、不支持 Release(int) 批量释放、不能替代独占锁(如写操作保护)

性能差距有多大?别靠猜

实测数据(times = 0xFFFFF ≈ 104万 次临界区进入)显示:lock/Monitor 耗时约 1.3 秒;SemaphoreSlim 约 2.7 秒;MutexSemaphore 则超过 13 秒——量级差异。这不是微优化,是选错原语直接拖垮吞吐量。

企业黄页-大众投资指南整站 asp.net 2.0
企业黄页-大众投资指南整站 asp.net 2.0

大众投资指南是基于Asp.Net(2.0)+C#+Access(sql2000)的企业黄页类程序,是基于web2.0 模式的网站。 贴吧和黄页都有采集功能 主程序包括分类信息和商家黄页两大模块。分类信息支持二级分类,商家黄页支持二级地区分类及二级行业分类。程序采用了伪静态(url重写)技术,可选生成纯静态首页。 一、分类信息仿百度贴吧编写,可以分别对游客及会员设置不同的审核条件。会员发布信息

下载
  • ? 关键区别:耗时主要来自系统调用开销。Mutex 每次 WaitOne() 都进内核;SemaphoreSlim 默认只在竞争激烈时才进
  • ? 参数陷阱:SemaphoreSlim(1, 1) 看似等价于 Mutex,但行为不同——它没所有权概念,也无需同一线程释放
  • ? 安全底线:若临界区执行时间 > 1ms,优先考虑 SemaphoreSlimlock;若 > 100ms,应重构逻辑,而非硬扛锁

一个常见错误:把 SemaphoreSlim 当成“可重入锁”用

SemaphoreSlim 不检查调用线程,也不记录谁获取了许可。这意味着:同一个线程反复 Wait() 会把自己卡住(计数归零后无法再进),除非你手动 Release() 多次——但它不会帮你记“进了几次”。这和 lockMonitor 的可重入性完全不同。

  • ❌ 错误写法:
    var sem = new SemaphoreSlim(1);
    sem.Wait(); // ✅
    sem.Wait(); // ❌ 死等(除非其他线程 Release)
  • ✅ 正确做法:明确设计为“资源配额”,不是“代码段保护”。例如控制最多 5 个数据库连接同时活跃,就初始化为 new SemaphoreSlim(5, 5)
  • ? 提示:如果真需要可重入 + 异步支持,用 AsyncLock(社区封装)或 ReaderWriterLockSlim(读多写少时)

最常被忽略的一点:Mutex 的异常安全极难保障——WaitOne() 成功后若中途抛异常,ReleaseMutex() 很容易漏掉;而 SemaphoreSlim 虽然没所有权,但至少不会因“忘记释放”导致全局阻塞——它只是让并发数暂时少一个。所以,宁可多花点时间封装 SemaphoreSlimusing 模式,也别裸写 Mutex

相关专题

更多
什么是中间件
什么是中间件

中间件是一种软件组件,充当不兼容组件之间的桥梁,提供额外服务,例如集成异构系统、提供常用服务、提高应用程序性能,以及简化应用程序开发。想了解更多中间件的相关内容,可以阅读本专题下面的文章。

175

2024.05.11

Golang 中间件开发与微服务架构
Golang 中间件开发与微服务架构

本专题系统讲解 Golang 在微服务架构中的中间件开发,包括日志处理、限流与熔断、认证与授权、服务监控、API 网关设计等常见中间件功能的实现。通过实战项目,帮助开发者理解如何使用 Go 编写高效、可扩展的中间件组件,并在微服务环境中进行灵活部署与管理。

212

2025.12.18

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

312

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

522

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

48

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

190

2025.08.29

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

471

2023.08.10

windows查看端口占用情况
windows查看端口占用情况

Windows端口可以认为是计算机与外界通讯交流的出入口。逻辑意义上的端口一般是指TCP/IP协议中的端口,端口号的范围从0到65535,比如用于浏览网页服务的80端口,用于FTP服务的21端口等等。怎么查看windows端口占用情况呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

516

2023.07.26

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

7

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 6.3万人学习

Excel 教程
Excel 教程

共162课时 | 10.2万人学习

PHP基础入门课程
PHP基础入门课程

共33课时 | 1.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号