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

进程互斥的软件实现方法

单标志法

算法思想:两个进程在访问完临界区后会把使用临界区的权限转交给另一个进程。也就是说每个进程进入临界区的权限只能被另一个进程赋予

int turn = 0; //turn 表示当前允许进入临界区的进程号P0 进程:
while (turn != 0);  ① //进入区
critical section;   ② //临界区
turn = 1;           ③ //退出区
remainder section;  ④ //剩余区P1进程:
while (turn != 1);  ⑤ //进入区
critical section;   ⑥ //临界区
turn = 0;           ⑦ //退出区
remainder section;  ⑧ //剩余区

turn 的初值为 0,即刚开始只允许 0 号进程进入临界区。 若 P1 先上处理机运行,则会一直卡在 ⑤。直到 P1 的时间片用完,发生调度,切换 P0 上处理机运行。代码 ① 不会卡住 P0,P0 可以正常访问临界区,在 P0 访问临界区期间即时切换回 P1,P1 依然会卡在 ⑤。只有 P0 在退出区将 turn 改为 1 后,P1 才能进入临界区。

因此,该算法可以实现“同一时刻最多只允许一个进程访问临界区”

存在的问题:

场景举例说明

让我们一步步模拟:

  1. 初始状态:

    • turn = 0 → 表示现在轮到 P0 可以进入临界区

    • P1 想进入临界区,于是执行 while (turn != 1),发现不满足,只能等待

    • P0 其实此时没什么事,不想进临界区,也不运行相关代码

  2. 结果:

    • P1 一直卡在 while (turn != 1),根本进不去临界区;

    • turn 又不会自动改变(P0 不进入临界区,就不会执行 turn = 1);

    • P1 陷入“饥饿”状态:它想进入,但“钥匙”还在 P0 手上;

    • 同时,P1 在那儿空等浪费 CPU(忙等待)→ 资源浪费

双标志先检查法

算法思想:
  • 每个进程设置一个布尔型变量 flag[i] 来表示自己是否想进入临界区

  • 进程在进入临界区之前,先检查另一个进程的 flag 值,看对方是否也想进入。

  • 如果对方也想进入,就进入忙等待

  • 如果对方没有想进入,则自己设置自己的 flagtrue,然后进入临界区。

设置一个布尔型数组 flag[],数组中各个元素用来标记各进程想进入临界区的意愿,比如“flag[0] = true”意味着 0 号进程 P0 现在想要进入临界区。每个进程在进入临界区之前先检查当前有没有别的进程想进入临界区,如果没有,则把自身对应的标志 flag[i] 设为 true,之后开始访问临界区。

bool flag[2]; //表示进入临界区意愿的数组
flag[0] = false;
flag[1] = false; //刚开始设置为两个进程都不想进入临界区P0 进程:
while (flag[1]); ①
flag[0] = true;  ②    //进入区
critical section; ③
flag[0] = false; ④
remainder section;P1 进程:
while (flag[0]); ⑤ //如果此时 P0 想进入临界区,P1 就一直循环等待
flag[1] = true;  ⑥ //标记为 P1 进程想要进入临界区  (进入区)
critical section; ⑦ //访问临界区
flag[1] = false; ⑧ //访问完临界区,修改标记为 P1 不想使用临界区
remainder section;
存在的问题

❗1. 不能保证互斥(互斥性失效)(按①⑤②⑥这样的顺序执行就会导致这样)

场景设定:

两个进程 P0 和 P1 几乎同时想进入临界区

步骤拆解:

  1. 系统调度让 P0 和 P1 几乎同时执行到 while(flag[对方])

    • P0 执行 while(flag[1]),发现 flag[1] == false(因为 P1 还没设置)

    • P1 执行 while(flag[0]),也发现 flag[0] == false(因为 P0 还没设置)

  2. 因此:

    • P0 认为 P1 没想进,就放心地执行 flag[0] = true

    • P1 也认为 P0 没想进,就也执行 flag[1] = true

  3. 结果:P0 和 P1 都设置了自己的 flagtrue,都进入了临界区!

  4. 互斥性就失败了:两个进程同时访问共享资源

若按照①⑤②⑥③⑦...的顺序执行,P0 和 P1 将会同时访问临界区。 因此,双标志先检查法的主要问题是:违反“忙则等待”原则。 原因在于,进入区的“检查”和“上锁”两个处理不是一气呵成的。“检查”后,“上锁”前可能发生进程切换。

双标志后检查法

算法思想:

先声明意图(上锁)再检查对方是否也要进。

这样做的原因是:
在先检查后上锁(比如前面的双标志先检查法)中,两个进程都可能误以为对方没想进,然后都进入临界区,违反了互斥原则。

所以这里改进成:

  1. 每个进程先把自己的 flag[i] 设置为 true,表示“我要进临界区”;

  2. 然后检查对方的 flag[j]

  3. 如果对方也想进,就等待;

  4. 如果对方不想进,就进入临界区。

bool flag[2]; //表示进入临界区意愿的数组
flag[0] = false;
flag[1] = false; //刚开始设置为两个进程都不想进入临界区P0 进程:
flag[0] = true;  ①
while (flag[1]); ②
critical section; ③
flag[0] = false; ④
remainder section;P1 进程:
flag[1] = true;  ⑤ //标记为 P1 进程想要进入临界区
while (flag[0]); ⑥ //如果 P0 也想进入临界区,则 P1 循环等待
critical section; ⑦ //访问临界区
flag[1] = false; ⑧ //访问完临界区,修改标记为 P1 不想使用临界区
remainder section;

若按照①⑤②⑥...的顺序执行,P0 和 P1 将都无法进入临界区 因此,双标志后检查法虽然解决了“忙则等待”的问题,但是又违背了“空闲让进”和“有限等待”原则,会因各进程都长期无法访问临界资源而产生“饥饿”现象。

如果两个进程同时几乎执行到①⑤这一步

  • P0 执行 flag[0] = true;

  • P1 执行 flag[1] = true;

  • 然后:

    • P0 进入 while (flag[1]);,发现 flag[1] == true → 开始等待

    • P1 进入 while (flag[0]);,发现 flag[0] == true → 也开始等待

于是,两个进程都在等待对方放弃进入临界区,但又谁都不愿意主动放弃 → 形成了“互相谦让”却“都进不去”的尴尬状态

这就是所谓的:

❗ 饥饿现象(Starvation)和活锁(Live Lock)

  • 饥饿(Starvation):进程长期得不到所需资源(临界区)

  • 活锁(Live Lock):进程虽然一直在“活动”地等待(没有卡死),但实际上也永远得不到执行的机会

Peterson 算法代码

bool flag[2] = {false, false}; // 表示两个进程是否想进
int turn = 0;                  // 表示让谁先进入(初始给 P0)// P0 进程:
flag[0] = true;      // ① 表示想进入临界区
turn = 1;            // ② 表示让对方先试
while (flag[1] && turn == 1);  // ③ 如果 P1 想进 且 turn 让 P1 先 → 等
critical section;   // ④ 临界区
flag[0] = false;     // ⑤ 退出临界区,表示不想进了// P1 进程:
flag[1] = true;
turn = 0;
while (flag[0] && turn == 0);
critical section;
flag[1] = false;

相关文章:

  • Spring 事务实现原理,Spring 的 ACID是如何实现的?如果让你用 JDBC 实现事务怎么实现?
  • 2025年NISP一级题库试题
  • 17.2Linux的MISC驱动实验(编程)_csdn
  • Nordic外设GPIO[nrfx_gpiote_in_init函数报NRFX_ERROR_NO_MEM并且fatal error]
  • 【c++深入系列】:万字string详解(附有sso优化版本的string模拟实现源码)
  • Centos 、Linux 基础运维命令
  • Spark-Streaming简介及核心编程
  • UML 通信图对象协作:共享汽车系统交互脉络
  • 算力网络有关论文自用笔记(2)
  • 何东山团队提到的“真正真空”(zero-point-free vacuum)
  • Power BI企业运营分析——数据大屏搭建思路
  • DeepSeek在自动驾驶领域的创新应用
  • DOCA介绍
  • move闯关 (集合)
  • 嘻游后台系统与机器人模块结构详解:功能逻辑 + 定制改造实战
  • java实现 PDF中的图片文字内容识别
  • Javase 基础入门 —— 02 基本数据类型
  • 联易融受邀参加上海审计局金融审计处专题交流座谈
  • 测试开发 - Java 自动化测试核心函数详解
  • 进阶算法 第一课:贪心
  • 新华时评:坚定不移办好自己的事,着力抓好“四稳”
  • 万能险新规落地:保险期限不得低于五年,明确万能险销售“负面清单”
  • 美联储官员:货币政策不会立即改变,金融市场波动或致美国经济增长承压
  • 一季度公募管理规模出炉:44家实现增长,4家规模环比翻倍
  • 贝壳:网传“深圳贝壳内部通知”不实
  • 解放日报:上海一季度GDP同比增长5.1%,两大新动能助推经济“开门红”