进程互斥的软件实现方法

单标志法

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

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;

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

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

相关文章

力扣150题-- 汇总区间和合并区间

Day 27 题目描述 思路 做法: 特殊处理空数组和数组只有一个元素的情况设置beg,end标记范围的起始和结束,x用来比较元素是否有序(初始end和beg都指向nums[0[,x为nums[0]1)遍历数组如果当前元素等于x,说明…

【c++深入系列】:万字string详解(附有sso优化版本的string模拟实现源码)

🔥 本文专栏:c 🌸作者主页:努力努力再努力wz 💪 今日博客励志语录: 当你想放弃时,想想为什么当初坚持走到了这里 ★★★ 本文前置知识: 类和对象(上) 类和对…

Spark-Streaming简介和核心编程

Spark-Streaming简介 概述:用于流式数据处理,支持Kafka、Flume等多种数据输入源,可使用Spark原语运算,结果能保存到HDFS、数据库等。它以DStream(离散化流)为抽象表示,是RDD在实时场景的封装&am…

verilog中的约束信息

1、保持约束 keep:当编译器在对FPGA设计进行映射时,一些线网将会被吸收到逻辑块中。 (* KEEP "{TRUE | FALSE}" *) keep_hierarchy:vivado默认会把设计变成一级一级模块化的调用转换为一个没有子模块的超大模块。这个约束会保留部分层级关系…

Missashe考研日记-day24

Missashe考研日记-day24 1 专业课408 学习时间:2h30min学习内容: 今天把剩下的两个经典同步问题和管程部分的课看了,然后做课后习题。这部分的重点在PV大题,很多很经典,不过第一轮不打算做大题,把选择题做…

力扣每日打卡17 49. 字母异位词分组 (中等)

力扣 49. 字母异位词分组 中等 前言一、题目内容二、解题方法1. 哈希函数2.官方题解2.1 前言2.2 方法一:排序2.2 方法二:计数 前言 这是刷算法题的第十七天,用到的语言是JS 题目:力扣 49. 字母异位词分组 (中等) 一、题目内容 给…

C#抽象类和虚方法的作用是什么?

抽象类 (abstract class): 不能直接实例化,只能被继承。 用来定义一套基础框架和规范,强制子类必须实现某些方法(抽象方法)。 可用来封装一些共通的逻辑,减少代码重复。 虚方法 (virtual): …

PowerBi中ALLEXCEPT怎么使用?

在 Power BI 的 DAX 中,ALLEXCEPT() 是一个非常重要的函数,用来实现**“在保留部分筛选条件的前提下,移除其他所有筛选器”**,它常用于 同比、占比、累计汇总 等分析中。 ✅ 一、ALLEXCEPT 是什么意思? 函数全称&…

IQ信号和实信号的关系与转换的matlab实现

IQ信号 IQ信号通常是指两路正交的信号(I路和Q路),在实际信号采样中,通常会进行IQ采样,将实信号转换为复基带信号进行存储。 IQ信号转实信号 IQ信号转为实信号,其实就是将IQ两路正交信号通过上变频合并为一个实数的带通信号,这通常在通信系统中用于将基带信号调制到载…

【锂电池剩余寿命预测】LSTM长短期记忆神经网络锂电池剩余寿命预测(Matlab源码)

目录 效果一览程序获取程序内容代码分享研究内容基于LSTM长短期记忆神经网络的锂电池剩余寿命预测摘要关键词1. 引言1.1 研究背景1.2 研究现状与问题1.3 研究目的与意义2. 文献综述2.1 锂电池剩余寿命预测方法概述2.2 传统预测方法的优势与不足2.3 LSTM在锂电池寿命预测中的应用…

具身智能的理论基础

引言 在人工智能与认知科学快速发展的背景下,“具身智能”(Embodied Intelligence)这一概念日益受到重视。具身智能是指智能体的认知能力不仅源于其大脑(或中央处理单元),更根植于其身体的结构、感官与其所…

【数据结构】励志大厂版·初级(二刷复习)双链表

前引:今天学习的双链表属于链表结构中最复杂的一种(带头双向循环链表),按照安排,我们会先进行复习,如何实现双链表,如基本的头插、头删、尾删、尾插,掌握每个细节,随后进…

CSS `display` 属性详解(完整版)

CSS display 属性详解(完整版) 1. 属性值及特性详解 display 属性控制元素的布局类型和生成的框类型,以下是 所有有效值 及其特性: 1.1 基础类型 值描述布局行为是否生成块级框典型用途block元素独占一行,宽度自动撑…

【数据结构 · 初阶】- 堆的实现

目录 一.初始化 二.插入 三.删除(堆顶、根) 四.整体代码 Heap.h Test.c Heap.c 我们使用顺序结构实现完全二叉树,也就是堆的实现 以前学的数据结构只是单纯的存储数据。堆除了存储数据,还有其他的价值——排序。是一个功能…

qt.tlsbackend.ossl: Failed to load libssl/libcrypto.

我的环境是windows,QT6.3.2(msvc2019_64/mingw_64) 出错原因 QT没有正确加载OpenSSL。 解决过程 1、确保安装的有openssl。 文章结尾有个注意,是其他方式安装过openssl,环境变量有,但是QT找不到的问题。…

【Linux】用户权限

shell命令 1. Linux本质上是一个操作系统,但是一般的用户不能直接使用它,而是需要通过外壳程序shell,来与Linux内核进行沟通。 2. shell的简单定义:命令行解释器。主要包含以下作用: 将使用者的命令翻译给核心处理。将…

赛灵思 XC7K325T-2FFG900I FPGA Xilinx Kintex‑7

XC7K325T-2FFG900I 是 Xilinx Kintex‑7 系列中一款工业级 (I) 高性能 FPGA,基于 28 nm HKMG HPL 工艺制程,核心电压标称 1.0 V,I/O 电压可在 0.97 V–1.03 V 之间灵活配置,并可在 –40 C 至 100 C 温度范围内稳定运行。该器件提供…

【题解-Acwing】847. 图中点的层次

题目:847. 图中点的层次 题目描述 给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环。 所有边的长度都是 1,点的编号为 1∼n。 请你求出 1 号点到 n 号点的最短距离,如果从 1 号点无法走到 n 号点,输出 −1 。 输入 第一行包含两个整数 n 和 m。 接下来 m 行…

css图片设为灰色

使用filter方式将图片设置为灰色 普通图片使用&#xff1a;filter: saturate(0); 纯白图片使用&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"width…

【Luogu】动态规划一

P5414 [YNOI2019] 排序 - 洛谷 思路&#xff1a; 可以想到对于任意一个需要换位置的数字&#xff0c;我们不可能换两次及以上&#xff0c;那么这题就可以转化为求一个最大和的最长不递减子序列&#xff0c;最后的答案就是众和减去这个最大和 代码&#xff1a; #include <…