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

Linux进程间通信——软件实现临界区互斥的基本方法

文章目录

    • 实现临界区互斥的基本方法
      • 软件实现
        • 单标志法
        • 双标志先检查法
        • 双标志后检查法
        • Peterson算法

实现临界区互斥的基本方法

我们说临界资源是在一段时间内只允许一个进程访问,而进程访问临界资源的那段代码称为临界区

为了防止两个进程同时进入临界区访问临界资源,我们设计的同步机制就需要满足下面的准则

  • 空闲让进:不能占着茅坑不拉屎,当临界区空闲时可以允许另一个进程请求并进入临界区
  • 忙则等待:不能别人上着呢冲进去也要拉,当临界区被占用时,其他请求访问的进程必须等待
  • 有限等待:不能让等待的人憋死了,防止进程饥饿,要保证进程能在有限的时间内进入临界区
  • 让权等待:不能占着临界区、阻塞了还得占着CPU,防止忙等待

软件实现

一般这种方法都是基于全局变量的,让全局变量作为标志位

单标志法

最简单的一个想法其实就是设一个bool变量,0时表示P0进程可以进入,1时表示P1进程可以进入,假设全局bool变量为flag

// P0进程
while(flag != 0); // 当flag不为0时,说明不允许P0进入临界区,则循环等待 进入区
// 访问临界资源... 临界区
flag = 1; // 访问完了 要让给P1进程访问了 退出区
// 其他代码 剩余区
// P1进程
while(flag != 1); // 当flag不为1时,说明不允许P1进入临界区,则循环等待 进入区
// 访问临界资源... 临界区
flag = 0; // 访问完了 要让给P0进程访问了 退出区
// 其他代码 剩余区

这个算法是能够实现每次只让其中一个进程访问临界区的,但是每次访问完之后,必须让对方用,因为只有对方能把flag设置为自己的数字

这就相当于自己拉完了让别人拉,但是如果别人一直不拉,自己想拉也不能再拉,因为对方没有先拉,只有对方拉完了之后自己才能被允许

这就违背了空闲让进的原则,容易造成资源利用不充分,而且也会造成进程饥饿

双标志先检查法

有了之前的经验之后,我们要解决遗留下来的问题,那就再设一个标志位,bool flag[2]

flag[0]表示P0进程进入临界区的意愿,flag[1]表示P1进程进入临界区的意愿

假如P0进程想访问临界区,就先查看P1进程是否想用(flag[1]是否为true),是的话就等待,不是的话就把自己的设为true,然后访问临界区,访问完之后把自己设为false

这就相当于一个人在拉之前先问一句,你要不要拉,你要拉的话那你先,你不拉那我要拉了,拉完之后跟他说拉完了,你可以去了

// P0
while(flag[1]); // 检查P1是否在拉,在的话一直循环等待 进入区
flag[0] = true; // 表示自己要拉,其他人要拉的话必须等待 进入区
// 访问临界区资源... 临界区
flag[0] = false; // 表示自己拉完了,对方可以去 退出区
// 其他代码 剩余区
// P1
while(flag[0]); // 检查P0是否在拉,在的话一直循环等待 进入区
flag[1] = true; // 表示自己要拉,其他人要拉的话必须等待 进入区
// 访问临界区资源... 临界区
flag[1] = false; // 表示自己拉完了,对方可以去 退出区
// 其他代码 剩余区

这个算法就完美解决了必须交替执行的问题,如果对方一直不想用的话自己就可以一直用了

但是别忘了进程是并发执行的,而且具有异步性,这就导致一个巨大的问题

一开始while循环的时候,两个标志位都是false,都没人要用,然后又几乎同时说自己要用就开始拉了,同时把标志位设置为true了

着就违反了忙则等待的原则,主要原因其实就是检查和设置的操作这个过程有可能会被中断并发换下来

双标志后检查法

那么把进入区的两行代码换一下呢

// P0
flag[0] = true; // 表示自己要拉,其他人要拉的话必须等待 进入区
while(flag[1]); // 检查P1是否在拉,在的话一直循环等待 进入区
// 访问临界区资源... 临界区
flag[0] = false; // 表示自己拉完了,对方可以去 退出区
// 其他代码 剩余区
// P1
flag[1] = true; // 表示自己要拉,其他人要拉的话必须等待 进入区
while(flag[0]); // 检查P0是否在拉,在的话一直循环等待 进入区
// 访问临界区资源... 临界区
flag[1] = false; // 表示自己拉完了,对方可以去 退出区
// 其他代码 剩余区

这就相当于先声明我要拉,后一步检查对方要不要,但是我们继续考虑并发的情况,如果两个进程几乎同时声明自己要拉,检查的时候两个进程都会一直循环等待,结果就导致谁都没办法拉了

这就违背了空闲让进的原则了,也就会导致饥饿现象

似乎进入了死局?

Peterson算法

既然两个标志不够完成我们的要求,三个标志足够吗

Peterson算法就是这么干的,利用flag[2]表示想不想拉,用turn表示有没有进去拉,这样就把有限等待和空闲让进都解决了

// P0
flag[0] = true; // 表示自己想拉
turn = 1; // 表示对方可以拉,谦让一下
while(flag[1]&&turn==1); // 如果对方谦让了,并且对方没有想拉,那自己就拉 进入区
// 访问临界资源... 临界区
flag[0] = false; // 表示自己拉完了 退出区
// 其他代码 剩余区
// P1
flag[1] = true; // 表示自己想拉
turn = 0; // 表示对方可以拉,谦让一下
while(flag[0]&&turn==0); // 如果对方谦让了,并且对方没有想拉,那自己就拉 进入区
// 访问临界资源... 临界区
flag[1] = false; // 表示自己拉完了 退出区
// 其他代码 剩余区

即便两个进程并发执行,turn也只有一个值,也就是两个循环必定会走一个,就完美的遵循了前三个原则,但还没有完成让权等待的功能

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 高性能web服务器3——Nginx编译安装
  • Spring MVC Controller返回json日期格式配置失效的解决办法
  • CUDA编程07 - 卷积的优化
  • TikTok达人营销与品牌建设:长期视角下的策略布局
  • Zookeeper服务注册及心跳机制详解
  • 【操作系统】什么是进程?什么是线程?两者有什么区别(面试常考!!!)
  • 设计模式---构建者模式(Builder Pattern)
  • 详解线索分层的目的、维度与创新实践
  • 【Java】了解线程 Thread 类的使用,如何创建、终止、等待一个线程,一文读懂不迷路
  • 【论文学习与撰写】快捷搜索指令filetype:pdf,搜索引擎关键词搜索pdf格式文件或者word格式文件。文献搜索方法大全。
  • 26 slave写入数据解决与GTIDS主从复制搭建
  • 白骑士的C#教学实战项目篇 4.4 游戏开发
  • 《向量数据库指南》——解决方案:采用安全、高性能的Milvus Cloud向量数据库,赋能Dopple AI的创新与发展
  • 速盾:博客主机租用怎么提高访问速度呢?
  • “LOCAL_LISTENER”参数导致业务无法连接数据库,文末附Oracle连接故障检查监听的排查流程
  • Angular2开发踩坑系列-生产环境编译
  • golang中接口赋值与方法集
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 使用API自动生成工具优化前端工作流
  • 微信公众号开发小记——5.python微信红包
  • 远离DoS攻击 Windows Server 2016发布DNS政策
  • 走向全栈之MongoDB的使用
  • ​​​【收录 Hello 算法】9.4 小结
  • #QT 笔记一
  • (01)ORB-SLAM2源码无死角解析-(66) BA优化(g2o)→闭环线程:Optimizer::GlobalBundleAdjustemnt→全局优化
  • (1)安装hadoop之虚拟机准备(配置IP与主机名)
  • (超详细)语音信号处理之特征提取
  • (附源码)计算机毕业设计ssm基于Internet快递柜管理系统
  • (利用IDEA+Maven)定制属于自己的jar包
  • (排序详解之 堆排序)
  • (四)JPA - JQPL 实现增删改查
  • (学习日记)2024.01.19
  • (一)springboot2.7.6集成activit5.23.0之集成引擎
  • . ./ bash dash source 这五种执行shell脚本方式 区别
  • ./configure,make,make install的作用(转)
  • .NET CORE Aws S3 使用
  • .NET 实现 NTFS 文件系统的硬链接 mklink /J(Junction)
  • .NET 使用配置文件
  • .NET/C# 推荐一个我设计的缓存类型(适合缓存反射等耗性能的操作,附用法)
  • .NetCore项目nginx发布
  • .NET上SQLite的连接
  • /proc/interrupts 和 /proc/stat 查看中断的情况
  • [ 转载 ] SharePoint 资料
  • [100天算法】-不同路径 III(day 73)
  • [3300万人的聊天室] 作为产品的上游公司该如何?
  • [ACP云计算]组件介绍
  • [C# WPF] DataGrid选中行或选中单元格的背景和字体颜色修改
  • [C#]winform部署yolov9的onnx模型
  • [C++] sqlite3_get_table 的使用
  • [Day 65] 區塊鏈與人工智能的聯動應用:理論、技術與實踐
  • [Doris]阿里云搭建Doris,测试环境1FE 1BE
  • [ERROR ImagePull]: failed to pull image k8s.gcr.io/kube-controller-manager失败
  • [E链表] lc83. 删除排序链表中的重复元素(单链表+模拟)
  • [Fri 26 Jun 2015 ~ Thu 2 Jul 2015] Deep Learning in arxiv