互斥锁详解(操作系统os)

1. 互斥锁 (Mutex) - 档案室的“智能锁”

首先,我们给之前讨论的那些“锁”一个正式的名字:互斥锁 (Mutex)

  • 概念:你可以把它简单理解成档案室门上的一把“智能锁”。它只有两种状态:locked (已上锁) 或 unlocked (未上锁)。
  • 操作:它提供两个标准操作:
    • acquire() (或 lock()):尝试获取锁。如果锁是开着的,你就把它锁上并进去。如果锁已经是锁着的状态,你就得等待。
    • release() (或 unlock()):你从档案室出来后,把锁打开。

这是一个非常通用的概念。之前我们学的所有方法,无论是软件的 Peterson 算法,还是硬件的 TSL/Swap 指令,它们本质上都是在实现一个“互斥锁”。

2. 互斥锁的“坏脾气”:忙等待与自旋锁 (Spinlock)

现在,关键问题来了:当 acquire() 失败时,进程该如何“等待”?

之前我们学到的所有软件和硬件实现方法,都有一个共同的特点:它们采用的是一种非常“执着”的等待方式。

  • 忙等待 (Busy-Waiting):当进程发现门是锁着的,它不会走开,而是在门口不停地、反复地检查:“门开了吗?开了吗?现在呢?”。这个过程,进程的CPU并没有闲着,而是在一个死循环里空转。
  • 自旋锁 (Spinlock):因为这种等待方式就像一个陀螺在原地不停地“旋转”一样,所以,我们把采用这种“忙等待”策略来实现的互斥锁,特别称为“自旋锁”。

所以,视频里提到的TSL指令、Swap指令,甚至Peterson算法,它们实现的都是自旋锁。它们都存在忙等待问题,违反了“让权等待”原则。


3. 自旋锁的成本与收益:一场“空转”与“切换”的赛跑

既然自旋锁会导致CPU空转,浪费资源,为什么我们还要用它呢?难道就没有更好的办法吗?

有!更好的办法就是我们之前提到的“让权等待”:进程发现门锁着,就去旁边的休息室睡觉(进入阻塞态),把CPU让给别人。等门开了,再由别人唤醒。

但是,“去睡觉再被叫醒”这个过程是有成本的,这个成本叫做“进程上下文切换”。它非常昂贵,好比:

  1. 你把办公桌上所有文件、电脑状态全部打包收好(保存现场)。
  2. 走到休息室(切换到内核态)。
  3. 找到一个空沙发躺下(进入阻塞队列)。
  4. 等别人叫醒你后,你再走回办公室(切换回用户态)。
  5. 再把所有文件和电脑状态全部恢复原样(恢复现场)。

这个过程比你单纯在门口站着“空转”几圈要复杂得多!

于是,我们就面临一个选择:

  • 选择自旋:付出“CPU空转”的代价。
  • 选择睡眠:付出“两次上下文切换”的代价。

到底哪个更划算?这取决于门要锁多久


4. 场景决定策略:单核 vs. 多核

这个选择在单核与多核系统上,答案是截然不同的。

在单处理机系统(一个打工人)
  • 场景:办公室只有一个打工人。他想进档案室,发现门被另一个任务锁着了。如果他选择“自旋”,会发生什么?
  • 灾难性后果:他会一直占用着办公室里唯一的CPU资源,在门口空转。而那个锁着门的任务,因为得不到CPU,根本无法运行,也就永远无法出来开门!只有等这个自旋的进程时间片用完,被强制换下,那个锁门进程才有机会上CPU去开锁。
  • 结论:在单核系统里,自旋等待毫无意义,纯属浪费。因为你等的那个锁,绝对不可能在你自旋的时候被解开。所以,在单核系统里,等待时必须“让权等待”(去睡觉)。
在多处理机系统(多个打工人)
  • 场景:办公室里有两个打工人(CPU 0 和 CPU 1)。进程A在CPU 0上运行,它想进档案室,发现门被正在CPU 1上运行的进程B锁着了。如果进程A选择“自旋”,会发生什么?
  • 可能的高效结果
    1. 进程A在CPU 0上开始自旋,占用了CPU 0。
    2. 与此同时,进程B正在CPU 1上继续运行!
    3. 如果进程B在档案室里的工作很简单,可能只需要几微秒就完成了。它在CPU 1上运行完,把门打开。
    4. CPU 0上的进程A在下一圈检查时,立刻就发现门开了,马上就能进去。
  • 结论:在这种情况下,进程A只“空转”了非常短的时间,这个代价远比进行一次昂贵的“上下文切换”要小得多。
  • 适用性:因此,自旋锁非常适合多处理器系统,但有一个重要前提:我们能预测锁被占用的时间非常短。比如,内核里修改一个指针,可能就几条指令的时间,用自旋锁就非常划算。

必会题与详解

题目一:什么是自旋锁?它与我们常说的“睡眠锁”(采用让权等待的锁)最核心的区别是什么?

答案详解

  1. 自旋锁 (Spinlock):是一种互斥锁的实现方式。当一个进程尝试获取锁失败时,它不会放弃CPU,而是进入一个“忙等待”循环,反复检查锁的状态,直到获取成功。
  2. 核心区别:它们在获取锁失败后的等待策略不同。
    • 自旋锁采用忙等待。进程保持在运行态,持续占用CPU进行空转。
    • 睡眠锁(如Semaphore、Mutex的非自旋实现)采用让权等待。进程会放弃CPU,从运行态转为阻塞态,进入等待队列,直到被其他进程唤醒。
    • 这个区别导致了它们的性能代价不同:自旋锁的代价是CPU空转时间,睡眠锁的代价是进程上下文切换的开销。

题目二:为什么说“自旋锁是为多处理器系统量身定做的”?在什么情况下,在多处理器系统中使用自旋锁是高效的?

答案详解

  1. 原-因:自旋锁的有效性依赖于一个核心前提:一个进程在等待锁的时候,另一个持有锁的进程能够同时在运行,以便尽快释放锁。这个“同时运行”的条件只有在多处理器系统中才能满足。在单处理器系统中,持有锁的进程无法与等待锁的进程同时运行,导致自旋等待变得毫无意义。

  2. 高效的情况:在多处理器系统中,当能够合理预期锁被占用的时间非常短时,使用自旋锁是高效的。因为如果锁很快被释放,那么等待进程自旋所消耗的CPU时间成本,将远小于进行两次昂贵的进程上下文切换(一次睡眠,一次唤醒)的成本。反之,如果锁被占用的时间很长,那么长时间的CPU空转会造成巨大浪费,此时采用睡眠锁让出CPU会更划算。

题目三:一个进程在使用自旋锁进行忙等待时,是否会一直霸占CPU直到它获得锁为止?请解释原因。

答案详解

不会。 一个用户态进程(或即使是内核态任务,在可抢占内核中)在使用自旋锁忙等待时,并不会无限期地霸占CPU。

原因是操作系统基于时间片轮转的抢占式调度机制依然在起作用。当该进程的时间片用完后,无论它是否在忙等待,时钟中断都会发生,调度程序会被触发,并强制将该进程从运行态切换下来,让它回到就绪队列。然后调度另一个进程上CPU运行。

所以,进程的忙等待只是在其被分配到的CPU时间片内进行空转。它并不能破坏操作系统的调度公平性,但它确实浪费了它“本应”用来做有意义计算的CPU时间。

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

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

相关文章

自动润滑系统:从 “盲目养护“ 到智能精注的工业运维革命

​在工业运维的漫长历史中,传统润滑模式如同"定时喂饭"——无论设备实际需求,仅凭经验或固定周期执行润滑作业。这种模式埋下两大隐患:过度润滑:某汽车生产线曾因季度性强制润滑,每年浪费1.2吨润滑脂&#x…

【Java八股文总结 — 包学会】(二)计算机网络

1.一条url输入到浏览器最后显示页面的过程 URL解析与处理 浏览器解析URL(如https://www.example.com/page) 分离协议(https)、域名(www.example.com)和资源路径(/page) 检查HSTS预加…

力扣61.旋转链表

给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。示例 1:输入:head [1,2,3,4,5], k 2 输出:[4,5,1,2,3]示例 2:输入:head [0,1,2], k 4 输出:[2,0,1]提示…

深度剖析:std::vector 内存机制与 push_back 扩容策略

深度剖析:std::vector 内存机制与 push_back 扩容策略 1. std::vector 核心内部结构 #mermaid-svg-8HOj3MqsD6UVgEeA {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-8HOj3MqsD6UVgEeA .error-icon{fill:…

GROW领导力模型

GROW领导力模型是由英国教练格雷厄姆亚历山大(Graham Alexander)、艾伦Fine和约翰惠特默(John Whitmore)在20世纪80年代提出的,最初用于体育教练领域,后来被广泛应用于企业管理、领导力发展和个人成长中。它…

打破并发瓶颈:虚拟线程实现详解与传统线程模型的性能对比

目录 一、定义与特性 二、虚拟线程实现 2.1 使用 Thread.startVirtualThread() 创建 2.2 使用 Thread.ofVirtual() 创建 2.3 使用 ThreadFactory 创建 2.4 使用 Executors.newVirtualThreadPerTaskExecutor()创建 三、虚拟线程和普通线程的区别 3.1 线程管理方式不同 3…

“28项评测23项SOTA——GLM-4.1V-9B-Thinking本地部署教程:10B级视觉语言模型的性能天花板!

一、模型介绍 GLM-4.1V-9B-Thinking是由智谱AI联合清华大学团队推出的多模态大模型,以GLM-4-9B-0414基座模型为底,通过引入“思维链推理机制”和“课程采样强化学习策略”(Reinforcement Learning with Curriculum Sampling)&…

推荐系统-Random算法

Random算法总结引言 在推荐系统研究与应用中,我们常常需要一些简单的基线算法来衡量更复杂算法的性能提升。Random(随机推荐)算法是最基础的基线方法之一,它通过随机生成评分来模拟用户对物品的偏好。虽然这种方法看似简单&#x…

Django--02模型和管理站点

Django–02模型与站点管理 Part 2: Models and the admin site 本教程承接Django–01的内容。我们将设置数据库、创建你的第一个模型,并快速了解 Django 自动生成的管理站点。 文章目录Django--02模型与站点管理前言一、设置数据库1.1 参考文档链接1.2 默认设置1.3…

CS课程项目设计1:交互友好的井字棋游戏

最近突然想开设一个专栏了,专门为计算机专业的同行分享一些入门级的课程项目设计,旨在让同学更好地了解CS项目的设计流程,同时给出代码来介绍coding过程。 今天要分享的是第一个CS课程项目:交互友好的井字棋游戏。 1. 研究目的 井…

首个自动驾驶VLA综述介绍

当视觉(Vision)、语言(Language)和行动(Action)三大能力在一个模型中融合,自动驾驶的未来将走向何方? 近日,来自麦吉尔大学、清华大学、小米公司和威斯康辛麦迪逊的研究团队联合发布了全球首篇针对自动驾驶领域的视觉-语言-行动(Vision-Language-Action, VLA)模型的…

C# 接口(接口可以继承接口)

接口可以继承接口 之前我们已经知道接口实现可以从基类被继承,而接口本身也可以从一个或多个接口继承而来。要指定某个接口继承其他的接口,应在接口声明中把基接口名称以逗号分隔的列表形式 放在接口名称后面的冒号之后,如下所示。类在基类列…

linux----------------------线程同步与互斥(上)

1.线程互斥 1-1 进程线程间的互斥相关背景概念 临界资源:多线程执行流共享的资源就叫做临界资源 临界区:每个线程内部访问临界资源的代码就叫做临界区 互斥:任何时刻,互斥保证只有一个执行进入临界区,对临界资源起…

百度AI的开放新篇章:文心4.5本地化部署指南与未来生态战略展望

百度AI的开放新篇章:文心4.5本地化部署指南与未来生态战略展望 一起来玩转文心大模型吧👉文心大模型免费下载地址:https://ai.gitcode.com/theme/1939325484087291906 🌟 嗨,我是IRpickstars! &#x1f30…

笔记/sklearn中的数据划分方法

文章目录一、前言二、数据划分方法1. 留出法(Hold-out)2. K折交叉验证(K-Fold)3. 留一法(Leave-One-Out)三、总结一、前言 简要介绍数据划分在机器学习中的作用。 二、数据划分方法 1. 留出法&#xff0…

Android14 开屏页SplashScreen设置icon圆角的原理

简介 我们在看到一个应用在启动的时候会看到一个启动的icon,这个图标是应用的icon当然也是可以应用自己去控制的如 <item name="android:windowSplashScreenAnimatedIcon">@drawable/adas_icon</item> 图上的效果明显不理想,图标是自带圆角,而且还是…

flutter redux状态管理

&#x1f4da; Flutter 状态管理系列文章目录 Flutter 状态管理(setState、InheritedWidget、 Provider 、Riverpod、 BLoC / Cubit、 GetX 、MobX 、Redux) setState() 使用详解&#xff1a;原理及注意事项 InheritedWidget 组件使用及原理 Flutter 中 Provider 的使用、注…

AMIS全栈低代码开发

amis是百度开源的前端低代码框架&#xff0c;它通过JSON配置来生成各种后台页面&#xff0c;旨在简化前端开发过程&#xff0c;提高开发效率&#xff0c;降低开发门槛。以下是详细介绍&#xff1a; 核心特点&#xff1a; 可视化开发&#xff1a;允许开发者通过可视化方式构建页…

【Python基础】变量、运算与内存管理全解析

一、删除变量与垃圾回收&#xff1a;内存管理的底层逻辑 在Python中&#xff0c;变量是对象的引用&#xff0c;而不是对象本身。当我们不再需要某个变量时&#xff0c;可以用del语句删除它的引用&#xff0c;让垃圾回收机制&#xff08;GC&#xff09;自动清理无引用的对象。 1…

Spring Boot + Javacv-platform:解锁音视频处理的多元场景

Spring Boot Javacv-platform&#xff1a;解锁音视频处理的多元场景 一、引言 在当今数字化时代&#xff0c;音视频处理已成为众多应用场景中不可或缺的一部分&#xff0c;从在线教育、视频会议到短视频平台、智能安防等&#xff0c;音视频数据的处理与分析需求日益增长。Java…