当前位置: 首页 > news >正文

多线程六脉神剑第一剑:互斥锁 (Mutex)

文章目录

  • 1、举个栗子🌰
  • 2、Mutex 的核心本质
    • 2.1 内核对象
    • 2.2 状态流转
  • 3、底层原理
    • 3.1. 原子操作:一切的基石
    • 3.2 用户态优化:自旋等待
  • 4、Mutex 的关键特性
    • 4.1 线程所有权
    • 4.2 递归获取(Reentrancy)
    • 4.3 跨进程能力
  • 5、内核层面的工作原理
    • 5.1 等待队列管理
    • 5.2 上下文切换的成本
  • 6、Mutex 的适用场景与代价
  • 7、总结:Mutex 的本质

1、举个栗子🌰

想象一下:

场景1:公共卫生间

  • 卫生间只有一个坑位(共享资源)

  • 门锁就是 Mutex

  • 你想上厕所 → 检查门锁(尝试获取锁)

  • 如果锁着 → 等待(阻塞)

  • 如果开着 → 进去并锁门(获取锁成功)

  • 使用完毕 → 开门(释放锁)

这个过程的本质就是:通过一个物理标志(门锁状态)来保证同一时刻只有一个人能使用卫生间。

2、Mutex 的核心本质

2.1 内核对象

Mutex 的本质是 操作系统内核维护的一个数据结构

// 这不是真实代码,而是概念性表示
class MutexKernelObject
{bool IsLocked;           // 当前是否被锁定Thread OwnerThread;      // 当前拥有者线程Queue<Thread> WaitQueue; // 等待队列int RecursionCount;      // 重入计数(同一个线程多次获取)
}

2.2 状态流转

Mutex 只有两种基本状态:

  • 有信号状态(Signaled):锁可用,线程可以获取

  • 无信号状态(Non-signaled):锁被占用,线程需要等待

3、底层原理

3.1. 原子操作:一切的基石

在硬件层面,Mutex 依赖于 CPU 的原子指令

// 伪代码:硬件层面的原子比较交换
bool AtomicCompareExchange(ref int location, int expected, int newValue)
{// 这个操作在CPU级别是原子的,不会被线程调度打断// 如果 location == expected,则 location = newValue 并返回 true// 否则返回 false
}

为什么需要原子性?
看这个非原子操作的例子:

// 线程不安全!
if (!_isLocked)          // 步骤1:检查
{_isLocked = true;    // 步骤2:设置// 在两个步骤之间,可能被其他线程打断!
}

3.2 用户态优化:自旋等待

现代 Mutex 的实现通常采用 两阶段策略

class HybridMutex
{private int _userModeFlag;  // 用户态标志private KernelObject _kernelObject; // 内核对象public void Enter(){// 第一阶段:用户态自旋for (int i = 0; i < 100; i++) // 尝试100次{if (AtomicCompareExchange(ref _userModeFlag, 0, 1) == true){return; // 快速获取成功!}Thread.SpinWait(100); // 稍微等待}// 第二阶段:进入内核态KernelWait(_kernelObject);}
}

为什么这样设计?

  • 用户态自旋:避免昂贵的内核切换

  • 内核等待:避免长时间占用CPU

4、Mutex 的关键特性

4.1 线程所有权

Mutex mutex = new Mutex();void ThreadMethod()
{mutex.WaitOne();    // 获取锁try{// 这个线程"拥有"这个mutex// 只有这个线程能释放它CriticalSection();}finally{mutex.ReleaseMutex(); // 必须由拥有者释放}
}

所有权的重要性:

  • 防止其他线程误释放锁

  • 支持递归获取(同一线程多次获取)

4.2 递归获取(Reentrancy)

Mutex mutex = new Mutex();void RecursiveMethod(int depth)
{mutex.WaitOne(); // 第一次获取try{Console.WriteLine($"进入深度 {depth}");if (depth < 3){RecursiveMethod(depth + 1); // 递归调用,再次获取}Console.WriteLine($"退出深度 {depth}");}finally{mutex.ReleaseMutex(); // 每次获取都需要对应的释放}
}

递归计数机制:

线程A: WaitOne()   → 计数=1 (获取锁)
线程A: WaitOne()   → 计数=2 (递归获取)
线程A: Release()   → 计数=1
线程A: Release()   → 计数=0 (真正释放)

4.3 跨进程能力

这是 Mutex 与 lock 关键字的最大区别:

// 进程1
class Program1
{static void Main(){// 创建命名互斥体,跨进程可见Mutex mutex = new Mutex(false, "Global\\MyAppMutex");Console.WriteLine("进程1 启动,等待获取Mutex...");mutex.WaitOne();Console.WriteLine("进程1 获得Mutex,执行关键操作...");Thread.Sleep(5000);mutex.ReleaseMutex();Console.WriteLine("进程1 释放Mutex");}
}// 进程2  
class Program2
{static void Main(){// 打开同一个命名互斥体Mutex mutex = Mutex.OpenExisting("Global\\MyAppMutex");Console.WriteLine("进程2 启动,等待获取Mutex...");mutex.WaitOne(); // 会等待进程1释放Console.WriteLine("进程2 获得Mutex,执行关键操作...");mutex.ReleaseMutex();Console.WriteLine("进程2 释放Mutex");}
}

5、内核层面的工作原理

5.1 等待队列管理

当线程无法获取 Mutex 时:

// 概念性代码,展示内核如何管理等待
class KernelMutexManager
{void WaitForMutex(Thread thread, Mutex mutex){// 1. 将线程放入等待队列mutex.WaitQueue.Enqueue(thread);// 2. 将线程状态改为"等待"thread.State = ThreadState.Waiting;// 3. 触发线程调度,切换到其他线程ScheduleNextThread();}void ReleaseMutex(Thread owner, Mutex mutex){if (mutex.WaitQueue.Count > 0){// 唤醒等待队列中的一个线程Thread nextThread = mutex.WaitQueue.Dequeue();nextThread.State = ThreadState.Ready;// 转移所有权mutex.OwnerThread = nextThread;}else{// 没有等待者,标记为可用mutex.IsLocked = false;mutex.OwnerThread = null;}}
}

5.2 上下文切换的成本

获取 Mutex 的完整代价:

bool AcquireMutex()
{// 用户态尝试(快速路径)if (TryFastPath()) return true;// 慢速路径的代价:// 1. 从用户态切换到内核态(约1000-2000 CPU周期)// 2. 线程状态保存(寄存器、栈指针等)// 3. 加入等待队列// 4. 线程调度器选择新线程// 5. 新线程的上下文恢复return SlowPathAcquire();
}

6、Mutex 的适用场景与代价

适用场景:

  1. 跨进程同步:多个程序需要协调

  2. 长时间持有:锁需要持有较长时间

  3. 递归需求:同一线程需要多次获取

  4. 复杂的等待条件:需要精细的线程调度

性能代价:

// 各种锁的大致性能对比(数字越小性能越好)
Method                 | 时间(相对单位)
-----------------------|---------------
无竞争用户态锁         | 1
有竞争用户态锁         | 10-100  
Mutex(无竞争)        | 50-100
Mutex(有竞争)        | 1000-10000(包含上下文切换)

7、总结:Mutex 的本质

Mutex 的本质是一个由操作系统内核管理的、具有线程所有权和递归能力的、可跨进程使用的同步原语,它通过用户态快速路径和内核态慢速路径的结合,在保证正确性的同时尽可能提高性能。

简单来说,Mutex 就是:

  • 一个门票:谁拿着门票谁就能进入

  • 一个队列管理器:没门票的人排队等待

  • 一个所有权登记系统:记录当前门票属于谁

  • 一个跨进程信使:不同程序之间也能协调

http://www.dtcms.com/a/521673.html

相关文章:

  • 做关于星空的网站wordpress自动升级
  • SuperSonic提示词设计与实现深度解析
  • 重庆网站设计哪家好山东省建设厅特种作业证查询网站
  • python 中 TypeError: Object of type TestCase is not JSON serializable
  • 【大模型应用开发 9.LangGraph从入门到实战·下】
  • 网站建设制作一个网站的费用免费免备案域名
  • 网站链接优化网上商城 网站
  • 网站建好了怎么做淘宝客腾讯域名备案
  • 导购网站开发 源码wordpress中常用插件安装包
  • 5 Concepts and Conventions(概念和约定)
  • 韶关住房和城乡建设局网站软件wap网站
  • 58同城推广网站怎么做深圳网站建设raygf
  • 如何确保PDF转CAD后的比例准确?
  • 新手什么网站做外贸效果图网站推荐大全面包砖
  • html做网站需要服务器吗cn域名多少钱一年
  • 网站怎么做免费推广方案苏州协会网站建设
  • 网站开发后台技术h5企业模板网站
  • IDEA 启动前端项目 IDEA 切换分支
  • 沈阳网站维护公司网站优化系统
  • 【从零开始构建性能测试体系-08】如何诊断性能瓶颈:从服务器到数据库的全方位分析
  • 怎么设计网站页面南昌手机建站模板
  • wordpress几个网站共用用户白山镇seo快速排名
  • 多空谨慎致成交清冷!强撑指数稳局面!
  • javaweb调用dify接口并流式返回
  • 网站技术部做什么网站如何做入支付接口
  • 网站建设主流开发语言毕设帮做网站
  • 上海网站开发企业七牛wordpress后台无法登录
  • 什么网站能接工地做注册免费网站
  • 智慧物业管理系统优化营商环境
  • 1024是什么意思?