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

进程与线程:10 信号量临界区保护

课程引入:信号量保护的必要性

这一节我们要探讨信号量的保护问题,即如何保护信号量。上一课我们学习了信号量可实现同步,多个进程通过信号量的值来决定是否继续执行,从而实现有序推进。但如果没有这节课所讲的信号量保护机制,信号量将无法正常工作。完整的逻辑是靠临界区来保护信号量,靠信号量来实现进程之间的同步。接下来我们将围绕两个主题展开:一是为什么要保护信号量以及临界区概念的引出;二是实际中保护信号量、实现临界区的方法。

一、为什么要保护信号量在这里插入图片描述

信号量本质上是一个整形变量,通过对它的访问和修改,能够让多个进程有序推进。例如上节课提到的empty信号量,生产者和消费者都会查看它的值:当生产者看到empty的值为-1时,就知道缺少空闲单元,自己也会进入睡眠状态,并将其值改为-2;消费者看到empty的值为-1时,会唤醒睡眠的进程。
在这里插入图片描述

然而,这里存在一个关键问题:信号量的值必须正确,其表达的含义必须准确。因为多个进程不仅会读取信号量的值,还会对其进行修改。当多个进程共享操作、共同修改同一个信号量时,由于进程调度的不确定性,很容易导致信号量的值出错。

比如,生产者要对empty信号量进行减1操作,正常情况下是从内存中取出变量值到寄存器,减1后再存回内存。但如果在执行这个操作的过程中,发生进程调度切换,例如时间片到时,切换到另一个生产者进程继续执行相同的操作,就会出现语义错误。假设初始empty值为-1,第一个生产者执行到将值取到寄存器并减1后,还未将结果存回内存就被切换出去,此时寄存器中的值为-2,但内存中的empty值仍为-1。第二个生产者进程执行同样操作,最终内存中的empty值会被错误地修改为-2,而实际上应该是-3,这就导致信号量的值与实际表达的含义不符,后续必然会引发问题。
在这里插入图片描述
这种因共享数据未被保护,多个进程竞争修改而产生的错误,与调度顺序有关,并非编程错误,被称为竞争条件。试图通过添加空循环来改变调度方案,从而避免错误的方法是不可行的,因为进程调度具有不确定性,每次运行时的调度情况都可能不同,无法保证这种方法始终有效。在这里插入图片描述
所以,必须引入保护机制来确保信号量的正确性。

二、临界区概念的引出

为了解决信号量共享修改时的竞争问题,我们引入了临界区的概念。在这里插入图片描述
对于修改信号量的代码段,我们需要保证其执行的原子性,即要么一个进程完整地执行完这段代码,要么其他进程完全不执行,不允许在执行过程中被其他进程打断或干扰。

例如,当一个生产者进程进入修改empty信号量的代码段时,其他生产者或消费者进程不能同时进入它们对应的修改empty信号量的代码段。临界区就是这样一段代码,在一个进程执行它时,其他进程不能进入与之对应的临界区代码段。修改信号量的代码必须在临界区内执行,否则由于进程调度的不确定性,就会造成竞争错误,导致信号量语义不正确。

三、保护信号量的方法

在明确了保护信号量的必要性和临界区概念后,接下来我们探讨如何实现临界区,即进入和退出临界区的代码应该如何编写。实现临界区的代码需要满足三个条件:在这里插入图片描述

  1. 互斥进入:这是最基本的条件,同一时刻只能有一个进程进入临界区,确保共享资源不会被多个进程同时修改。
  2. 有空让进:当临界区空闲时,等待进入的进程应该能够及时进入,提高资源利用率。
  3. 有限等待:进程不能无限期地等待进入临界区,避免出现饥饿现象。
(一)软件方法
  1. 轮换法
    轮换法类似于值日,通过一个全局变量turn来控制进程进入临界区的顺序。当turn的值等于某个进程标识时,该进程可以进入临界区,否则就在循环中等待。从互斥进入的角度来看,通过反证法可以证明它满足这一条件,因为turn不可能同时等于两个不同的值,所以不会出现两个进程同时进入临界区的情况。
    在这里插入图片描述

但它不满足有空让进的条件。例如,一个进程进入临界区后,turn的值改变,如果该进程因某种原因阻塞,不再执行,即使此时临界区空闲,其他进程也无法进入,因为turn的值还未轮到它们。

  1. 标记法
    标记法通过设置标记变量来表示进程是否想进入临界区。每个进程在尝试进入临界区前,先将自己的标记变量设为true,然后检查其他进程的标记变量。如果发现其他进程也想进入(其标记变量为true),则自己等待;当进程退出临界区时,将自己的标记变量设为false
    在这里插入图片描述

同样用反证法可以证明它满足互斥进入条件。在这里插入图片描述
但它存在问题,可能出现两个进程同时设置标记,然后都发现对方也想进入,从而导致谁都无法进入临界区的情况,不满足有空让进条件,还可能造成无限等待。

  1. Peterson算法(值日加标记法)
    Peterson算法结合了轮换法和标记法的思想,是一种非对称的方法。在这里插入图片描述在这里插入图片描述
    每个进程在进入临界区前,先设置自己的标记表示想进入,然后检查另一个进程的标记以及turn变量的值。如果另一个进程也想进入且turn的值表明轮到对方,自己就等待;否则可以进入临界区。进程退出临界区时,修改turn的值,让另一个进程有机会进入。

在这里插入图片描述

经过分析可以发现,Peterson算法满足互斥进入、有空让进和有限等待三个条件,是一种正确的保护临界区的方法。但它只适用于两个进程的情况,对于多个进程,需要采用其他算法。

  1. 面包店算法
    面包店算法是将Peterson算法推广到多个进程的情况。在这里插入图片描述
    它借鉴现实中取号的方法,每个进程想进入临界区时先取一个号,号不为零表示想进入。每次让号最小的进程进入临界区,进程离开时将号设为零。在取号过程中,每次取得的号是当前最大号加一,保证了公平性和有序性。
    在这里插入图片描述

面包店算法也满足互斥进入、有空让进和有限等待条件,能够有效保护多个进程情况下的临界区。但它也存在一些问题,例如取号过程中可能会出现号溢出的情况,需要进行额外处理,而且实现相对复杂。

(二)硬件方法
  1. 关中断法
    我们知道,进程调度是通过中断触发的,例如时钟中断会导致时间片变化,进而引发进程调度。关中断法就是利用这一原理,在进程进入临界区前,通过硬件提供的指令(如cli)关闭中断,这样在临界区内执行代码时,就不会因为中断而发生进程调度,从而保证了临界区代码执行的原子性。进程退出临界区时,再通过指令(如sti)打开中断。
    在这里插入图片描述
    然而,关中断法在多CPU系统中不好用。因为每个CPU都有自己的中断寄存器,在一个CPU上关闭中断,无法阻止其他CPU上的进程调度,其他CPU仍然可以执行修改共享资源的代码,导致临界区保护失效。但在单CPU系统(如实验用的Linux 0.1)中,关中断法可以使用,并且在做相关实验时鼓励采用这种方法。

  2. 原子指令法
    原子指令法的核心思想是利用硬件提供的原子指令,将对信号量(类似于锁)的修改操作变成一个不可分割的指令执行过程。前面提到的锁本质上是一个变量,用于表示资源是否被占用,其概念与信号量类似,但如果用普通信号量去实现锁,会陷入无限循环的保护问题(修改信号量还需要其他信号量保护)。
    在这里插入图片描述

硬件原子指令能够保证对这个锁变量的修改要么完整执行,要么不执行,不会在执行中途被打断。例如test set原子指令,它可以检查锁是否被锁上,如果已被锁上,返回true,进程就在循环中等待;如果没锁上,返回false,同时将锁锁上,进程可以直接进入临界区。进程退出临界区时,再将锁打开。

原子指令法满足互斥进入条件,因为同一时刻只有一个进程能够成功执行原子指令获取锁,其他进程只能等待。

  1. 有空让进:临界区空闲(lockfalse )时,进程可通过 TestAndSet 指令获锁进入,原理上满足。
  2. 有限等待:多进程竞争锁,高并发下可能有进程长时间无法获锁,不满足。
  3. 多CPU适用性
    • 优势:原子指令保证锁操作一致性,维持互斥性。
    • 劣势:进程轮询浪费CPU资源,易致进程饥饿,调度开销大。

课程总结

这节课我们深入探讨了信号量的保护问题。总结起来,需要用临界区来保护信号量,而实现临界区的方法有面包店算法(软件方法)、开关中断法和硬件原子指令法(硬件方法),它们分别适用于不同的场合。当临界区成功保护信号量后,信号量在执行过程中语义就会正确,基于正确语义的信号量,就能实现进程在合适的时候阻塞、唤醒和推进,从而实现多个进程的合理同步与合作,这就是进程同步和合作的完整故事。

相关文章:

  • 【通用智能体】Serper API 详解:搜索引擎数据获取的核心工具
  • Redis 学习笔记 4:优惠券秒杀
  • GEE谷歌地球引擎批量下载逐日ERA5气象数据的方法
  • 《P4551 最长异或路径》
  • C语言之旅【6】--一维数组和二维数组
  • MyBatis(二)
  • AI Agent开发第70课-彻底消除RAG知识库幻觉(4)-解决知识库问答时语料“总重复”问题
  • 生成树的保护机制
  • 解决 Tailwind CSS 代码冗余问题
  • 功能安全管理
  • ES(ES2023/ES14)最新更新内容,及如何减少内耗
  • 《C++与OpenCV实战:图像增强大核心算法详解》​​
  • 设备预测性维护:从技术架构到工程实践,中讯烛龙如何实现停机时间锐减
  • 玄机-第二章日志分析-redis应急响应
  • Eigen与OpenCV矩阵操作全面对比:最大值、最小值、平均值
  • 时序数据库、实时数据库与实时数仓:如何为实时数据场景选择最佳解决方案?
  • 模拟电路中的电感:从“电磁倔驴“到“电路稳定器“的奇幻漂流
  • TYUT-企业级开发教程-第二章
  • MinIO:从入门到精通,解锁云原生存储的奥秘
  • Linux下 使用 SSH 完成 Git 绑定 GitHub
  • 浙江广厦:诚挚道歉,涉事责任人交公安机关
  • 解读|战国子弹库帛书漂泊海外79年今归国,追索仍将继续
  • 遭车祸罹难的村医遇“身份”难题:镇卫生院否认劳动关系,家属上诉后二审将开庭
  • 乌克兰谈判代表团由12人组成,乌防长率领
  • 湖北宜化拟斥资超32亿加价回购“弃子”,布局上游煤炭业务
  • 日本前卫艺术先驱群展上海:当具体派相遇古树古宅