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

补充:用信号量实现前驱关系

一:实现进程的前驱关系(多级同步问题)

进程的前驱关系,本质是 “多个进程间存在先后依赖”—— 比如进程 A 执行完才能执行进程 B,进程 B 执行完才能执行进程 C,就像 “流水线作业”,必须按顺序推进。而每一对 “前 - 后” 依赖,都是一个独立的同步问题,因此信号量的核心作用就是为每一对前驱关系 “保驾护航”。

1. 核心原理

实现前驱关系需遵循三步:

  1. 画前驱图:先梳理进程间的依赖关系,用箭头表示 “前操作→后操作”(箭头起点是 “前进程”,终点是 “后进程”);
  1. 设信号量:为每一对前驱关系设置一个同步信号量,初值均为 0(理由同同步问题:初始时 “后进程” 需等待 “前进程” 的触发信号);
  1. 加 P/V 操作:在 “前操作” 结束后执行 V 操作(释放信号,通知 “后进程” 可执行),在 “后操作” 开始前执行 P 操作(等待 “前进程” 的信号)。

2. 案例实操:三进程前驱关系

假设存在三个进程 P1、P2、P3,依赖关系为:P1 执行完→P2 和 P3 才能执行(前驱图如下),用信号量实现该逻辑。

(1)第一步:画前驱图
P1 → S1 → P2↓S2 → P3
  • 箭头 1:P1→P2,对应同步信号量 S1;
  • 箭头 2:P1→P3,对应同步信号量 S2。
(2)第二步:初始化信号量

根据规则,每对前驱关系的信号量初值为 0:

semaphore S1 = {0, NULL};  // 控制P1→P2的前驱关系
semaphore S2 = {0, NULL};  // 控制P1→P3的前驱关系
(3)第三步:添加 P/V 操作
  • P1(前进程):执行完自身任务后,需触发 P2 和 P3,因此在任务结束后执行 V (S1) 和 V (S2);
  • P2(后进程):需等待 P1 完成,因此在任务开始前执行 P (S1);
  • P3(后进程):需等待 P1 完成,因此在任务开始前执行 P (S2)。

代码逻辑如下:

// 进程P1(前进程,触发P2和P3)
void P1() {执行P1的任务...  // 如“读取数据到内存”V(S1);          // 释放S1,通知P2“P1已完成”V(S2);          // 释放S2,通知P3“P1已完成”
}// 进程P2(后进程,等待P1)
void P2() {P(S1);          // 等待S1信号(P1未执行完则阻塞)执行P2的任务...  // 如“处理P1读取的数据”
}// 进程P3(后进程,等待P1)
void P3() {P(S2);          // 等待S2信号(P1未执行完则阻塞)执行P3的任务...  // 如“备份P1读取的数据”
}
(4)逻辑验证
  • 初始时 S1=0、S2=0,P2 执行 P (S1) 后阻塞,P3 执行 P (S2) 后阻塞;
  • P1 执行完任务后,V (S1) 使 S1=1(P2 被唤醒,开始执行),V (S2) 使 S2=1(P3 被唤醒,开始执行);
  • 最终实现 “P1 完→P2、P3 同时执行” 的前驱关系,符合预期。

3. 进阶案例:四进程多级前驱关系

若进程依赖为:P1→P2→P3,P1→P4(前驱图如下),实现逻辑如下:

(1)前驱图与信号量设置
P1 → S1 → P2 → S3 → P3↓S2 → P4
  • 前驱对 1:P1→P2 → 信号量 S1(初值 0);
  • 前驱对 2:P1→P4 → 信号量 S2(初值 0);
  • 前驱对 3:P2→P3 → 信号量 S3(初值 0)。
(2)代码逻辑
semaphore S1=0, S2=0, S3=0;void P1() {执行P1任务...V(S1);  // 触发P2V(S2);  // 触发P4
}void P2() {P(S1);  // 等P1执行P2任务...V(S3);  // 触发P3
}void P3() {P(S3);  // 等P2执行P3任务...
}void P4() {P(S2);  // 等P1执行P4任务...
}

结论:无论多少级前驱关系,核心都是 “一对前驱对应一个信号量,前 V 后 P”,逻辑可无限复用。

八、多资源场景:信号量初值的灵活设置

之前的案例中,信号量初值非 0 即 1,但实际系统中常存在 “多份同类资源”(如 3 台打印机、5 个缓冲区),此时信号量的初值需等于资源总数,而非固定 0 或 1。

1. 核心

  • 若信号量表示 “资源数量”:初值 = 系统中该资源的总数量;
  • P 操作:申请 1 份资源(S--,S<0 则阻塞,等待其他进程释放);
  • V 操作:释放 1 份资源(S++,S<=0 则唤醒 1 个等待进程)。

2. 案例:3 台打印机的资源分配

系统有 3 台打印机(资源总数 = 3),用信号量实现多进程的资源申请与释放:

// 初始化信号量:初值=3(3台打印机)
semaphore printer = {3, NULL};// 进程A申请打印机
void ProcessA() {P(printer);      // 申请1台,printer=3-1=2(足够,直接使用)使用打印机...V(printer);      // 释放1台,printer=2+1=3
}// 进程B申请打印机
void ProcessB() {P(printer);      // 申请1台,printer=3-1=2(足够)使用打印机...V(printer);
}// 进程C申请打印机
void ProcessC() {P(printer);      // 申请1台,printer=3-1=2(足够)使用打印机...V(printer);
}// 进程D申请打印机(前3台被占用)
void ProcessD() {P(printer);      // 申请1台,printer=3-4=-1(不足,阻塞)使用打印机...    // 需等待A/B/C中任意一个释放V(printer);
}

注意:多资源场景下,信号量初值≠0/1,需根据资源总数设置,这是考试中区分 “单资源” 与 “多资源” 的关键标志。

九、信号量应用的易错点

1. 错误 1:P/V 操作不成对

  • 缺 P 操作:多个进程可同时进入临界区,互斥失效(如打印机被多个进程同时使用);
  • 缺 V 操作:信号量永远无法恢复初值,等待进程永久阻塞(如 mutex=0 后无 V 操作,所有进程卡在 P (mutex));
  • 避坑:写代码时先标注 “临界区 / 前操作 / 后操作”,再强制在对应位置添加 P/V,写完后检查成对性。

2. 错误 2:信号量初值设置错误

  • 互斥信号量设为 0:初始时无进程能进入临界区(P (mutex) 直接阻塞);
  • 同步信号量设为 1:“后进程” 无需等待,直接执行,同步关系失效;
  • 多资源信号量设为 1:仅能分配 1 份资源,浪费其他资源;
  • 避坑:牢记 “三对应”—— 互斥→1,同步 / 前驱→0,多资源→资源总数。

3. 错误 3:P/V 操作顺序颠倒

  • 互斥场景:先 V 后 P(如先 V (mutex) 再 P (mutex)),会导致多个进程同时进入临界区;
  • 同步场景:先 P 后 V(如 “后进程” 先 P,“前进程” 后 V 是正确的,但 “前进程” 先 P 则会阻塞);
  • 避坑:按 “申请→使用→释放” 逻辑:互斥(P→临界区→V),同步(前 V→后 P)。

十、总结

http://www.xdnf.cn/news/17993.html

相关文章:

  • 【架构师干货】数据库管理系统
  • JavaWeb前端(HTML,CSS具体案例)
  • 火狐(Mozilla Firefox)浏览器离线安装包下载
  • 【JavaEE】多线程 -- 单例模式
  • 2025:AI狂飙下的焦虑与追问
  • SWE-bench:真实世界软件工程任务的“试金石”
  • GANs生成对抗网络生成手写数字的Pytorch实现
  • 原型和原型链的问题
  • mac电脑开发嵌入式基于Clion(stm32CubeMX)
  • ThinkPHP8学习篇(三):控制器
  • 《解构WebSocket断网重连:指数退避算法的前端工业级实践指南》
  • pair之于vector、queue(vector<pair<int,int>>)
  • Yolov模型的演变
  • K8S集群环境搭建
  • 【LeetCode 热题 100】(八)二叉树
  • 数据结构——栈和队列oj练习
  • 深度解析 Spring Bean 生命周期
  • 【网络安全】Webshell的绕过——绕过动态检测引擎WAF-缓存绕过(Hash碰撞)
  • 《P4180 [BJWC2010] 严格次小生成树》
  • MySQL 插入数据提示字段超出范围?一招解决 DECIMAL 类型踩坑
  • 安卓11 12系统修改定制化_____修改运营商版本安装特定应用时的默认规则
  • 机器学习相关算法:回溯算法 贪心算法 回归算法(线性回归) 算法超参数 多项式时间 朴素贝叶斯分类算法
  • 一文速通Python并行计算:14 Python异步编程-协程的管理和调度
  • C语言:文件操作详解
  • 后量子密码算法SLH-DSA介绍及开源代码实现
  • Java8~Java21重要新特性
  • C++ 最短路Dijkstra
  • CodeBuddy IDE深度体验:AI驱动的全栈开发新时代
  • Maven下载和配置-IDEA使用
  • 【算法】——力扣hot100常用算法技巧