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

用信号量实现进程互斥,进程同步,进程前驱关系(操作系统os)

用一个大家都很熟悉的场景来贯穿这三种应用:准备一场团队聚餐

  • 进程:团队里的每个成员(小明、小红、小刚等)。
  • 任务:买菜、洗菜、切菜、炒菜、摆碗筷等。

1. 用信号量实现进程互斥 - “厨房只有一个灶台,大家轮流用”

在我们的聚餐准备中,灶台就是那个最关键的临界资源,一次只能有一个人炒菜。如果小明和小红同时去炒菜,那锅就得飞起来了。

  • 实现步骤

    1. 划定临界区:找到那段必须互斥执行的代码,也就是“炒菜”这个动作。
    2. 设定互斥信号量:我们引入一个专门用于“灶台使用权”的信号量,叫 mutex_stove,它的初始值设为 1。这个1就代表“当前有1个可用的灶台名额”。
    3. 在临界区前后加上P、V操作
      • 任何一个人想炒菜(进入临界区)之前,必须先执行 P(mutex_stove)。这个P操作的意思是“申请一个灶台名额”。如果名额有(value从1变0),就进去炒。如果名额没了(value从0变-1),就去旁边等着(阻塞)。
      • 炒完菜(退出临界区)之后,必须立刻执行 V(mutex_stove)。这个V操作的意思是“归还灶台名额”。这会让value加1,如果有人在等,就能把他唤醒。
  • 代码框架

    semaphore mutex_stove = 1; // 互斥信号量,初值为1Process_小明() {...P(mutex_stove); // 申请使用灶台// --- 临界区开始 ---炒菜();// --- 临界区结束 ---V(mutex_stove); // 释放灶台...
    }Process_小红() {...P(mutex_stove); // 申请使用灶台// --- 临界区开始 ---炒菜();// --- 临界区结束 ---V(mutex_stove); // 释放灶台...
    }
    
  • 关键点

    • 互斥信号量的初始值永远是1
    • P、V操作必须成对出现。忘了P,大家就一起冲进去炒菜了;忘了V,第一个用完灶台的人就把门锁死,谁也别想再用了。

2. 用信号量实现进程同步 - “必须先洗完菜,才能切菜”

现在,我们有了更复杂的协作要求。团队里,小明负责洗菜小红负责切菜。这个顺序是绝对不能乱的,你不能切一堆带着泥的土豆。

  • 实现步骤

    1. 分析制约关系:明确哪个动作是“前操作”(洗菜),哪个是“后操作”(切菜)。
    2. 设定同步信号量:我们引入一个专门用于“洗菜完成”这个信号的信号量,叫 vegetable_washed,它的初始值设为 0。这个0代表“默认情况下,菜还没洗好”。
    3. 遵循“前V后P”原则
      • 前操作之后,执行V操作:小明洗完菜后,他要“吼一嗓子”,告诉大家菜洗好了。这个动作就是 V(vegetable_washed)。它会把信号量value从0变成1,表示“有1份洗好的菜可以用了”。
      • 后操作之前,执行P操作:小红在准备切菜之前,她必须先等待“菜洗好了”这个信号。这个动作就是 P(vegetable_washed)。如果信号量是0(菜没洗好),她就会在这里被阻塞。直到小明执行了V操作,信号量变成1,她才能通过P操作,开始切菜。
  • 代码框架

    semaphore vegetable_washed = 0; // 同步信号量,初值为0Process_小明() { // 前驱进程...洗菜();V(vegetable_washed); // 发出“菜已洗好”的信号...
    }Process_小红() { // 后继进程...P(vegetable_washed); // 等待“菜已洗好”的信号切菜();...
    }
    
  • 关键点

    • 同步信号量的初始值通常是0
    • 记住这个口诀:“前V后P”。前驱任务做完后V,后继任务开始前P。

3. 用信号量实现前驱关系 - “复杂的流水线作业”

现在,我们的聚餐准备工作形成了一个复杂的流程图(前驱图):

  1. S1: 买菜
  2. S2: 洗菜 (必须等S1完成)
  3. S3: 洗锅 (必须等S1完成)
  4. S4: 切菜 (必须等S2完成)
  5. S5: 准备调料 (必须等S3完成)
  6. S6: 炒菜 (必须等S4和S5都完成)

这本质上就是一连串的同步问题。

  • 实现步骤

    • 为每一对直接制约关系设立一个同步信号量
      • S1 -> S2:需要一个信号量 s12
      • S1 -> S3:需要一个信号量 s13
      • S2 -> S4:需要一个信号量 s24
      • S3 -> S5:需要一个信号量 s35
      • S4 -> S6:需要一个信号量 s46
      • S5 -> S6:需要一个信号量 s56
    • 所有这些同步信号量的初始值都设为 0
    • 对每一条“弧线”,都应用“前V后P”原则
  • 代码框架(重点看S1, S6)

    // 声明所有需要的同步信号量,初值都为0
    semaphore s12=0, s13=0, s24=0, s35=0, s46=0, s56=0;S1_买菜() {买菜();V(s12); // 通知S2可以开始了V(s13); // 通知S3可以开始了
    }// ... S2, S3, S4, S5 的代码省略,都是标准的前V后P ...S6_炒菜() {P(s46); // 等待S4(切菜)完成P(s56); // 等待S5(备调料)完成炒菜();
    }
    
  • 关键点

    • 一个任务有多少个直接后继,它后面就要跟多少个V操作。
    • 一个任务有多少个直接前驱,它前面就要有多少个P操作。

必会题与详解

题目一:在使用信号量实现进程互斥时,为什么互斥信号量mutex的初始值必须是1?如果设为0或2会发生什么?

答案详解

互斥信号量mutex的值代表“允许进入临界区的名额数量”。

  1. 初始值必须是1:因为我们希望在任何时候,最多只允许一个进程进入临界区。初始值为1,表示一开始有1个名额。第一个进程执行P操作后,mutex变为0,名额用完。其他进程再执行P操作就会被阻塞,从而保证了互斥。

  2. 如果设为0:表示一开始就没有任何名额。那么第一个到达的进程执行P(mutex)时,mutex会从0变为-1,该进程会被立即阻塞。结果就是没有任何进程能够进入临界区,系统陷入死锁。

  3. 如果设为2:表示一开始有2个名额。第一个进程执行P(mutex)后,mutex变为1。第二个进程执行P(mutex)后,mutex变为0。这意味着系统将允许两个进程同时进入临界区,这完全违背了“互斥”的初衷,会导致对临界资源的访问发生混乱。

题目二:在实现“进程A执行完代码a1后,进程B才能执行代码b1”这一同步关系时,同步信号量S的初始值应该是什么?P(S)和V(S)应该分别放在哪个位置?请解释原因。

答案详解

  1. 初始值:同步信号量S的初始值应该设为 0。这代表一个“消息”或“事件”的初始状态是“未发生”。在这里,它表示“进程A的代码a1尚未完成”。

  2. P、V操作的位置

    • V(S) 应该放在进程A的代码a1之后
    • P(S) 应该放在进程B的代码b1之前
  3. 原因(遵循“前V后P”原则):

    • 进程B是后继进程,它依赖于进程A的完成。因此,B在执行b1前必须“等待”一个信号,这个等待动作就是P(S)。由于S初始为0,进程B会在此处阻塞,直到S的值变为正数。
    • 进程A是前驱进程,它在完成a1后,有责任“发送”一个信号来通知B可以继续了。这个发送信号的动作就是V(S)。它会使S的值从0变为1,从而唤醒正在等待P(S)的进程B,使得B可以越过P操作,继续执行b1。这个机制保证了正确的执行顺序。
http://www.xdnf.cn/news/1116541.html

相关文章:

  • hercules zos 安裝 jdk 8
  • CTFSHOW pwn161 WP
  • 整流电路Multisim电路仿真实验汇总——硬件工程师笔记
  • 使用macvlan实现容器的跨主机通信
  • KL散度:信息差异的量化标尺 | 从概率分布对齐到模型优化的核心度量
  • C++高频知识点(十一)
  • ALB、NLB、CLB 负载均衡深度剖析
  • 开源工具DeepFilterNet:实时语音降噪
  • 更换docker工作目录
  • 06.计算两个日期之间的差值
  • lambdastream深入剖析
  • 【LeetCode100】--- 4.移动零【复习回顾】
  • mmap映射文件
  • 理解 Robots 协议:爬虫该遵守的“游戏规则”
  • HTML 标题标签
  • AI驱动的软件工程(上):人机协同的设计与建模
  • Python 学习之路(十)--常见算法实现原理及解析
  • 深度学习-循环神经网络RNN
  • 谷歌推出Vertex AI Memory Bank:为AI智能体带来持久记忆,支持连续对话
  • MongoDB性能优化实战指南:原理、实践与案例
  • RedisJSON 技术揭秘(五)`JSON.ARRPOP` 原子弹出 修改数组的终极手段
  • Java设计模式之行为型模式(命令模式)介绍与说明
  • 串口A和S的含义以及RT的含义
  • 深入理解观察者模式:构建松耦合的交互系统
  • 设计模式深度解析:单例、工厂、适配器与代理模式
  • Word中的批注显示与修订显示
  • STM32 | HC-SR04 超声波传感器测距
  • 洛谷 P13014:[GESP202506 五级] 最大公因数
  • CentOS系统下前后端项目部署攻略
  • 【MLLM】多模态理解GLM-4.1V-Thinking模型