ucore—17至20讲:同步互斥、信号量、死锁、进程通信

2024-02-07 02:18

本文主要是介绍ucore—17至20讲:同步互斥、信号量、死锁、进程通信,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 第十七讲:同步互斥
    • 17.1 背景
    • 17.2 现实生活中的同步问题
    • 17.3 临界区及同步实现方式
      • 17.3.1 临界区
      • 17.3.2 禁用硬件中断实现同步
      • 17.3.3 基于软件的同步
      • 17.3.4 高级抽象的同步方法(锁)
  • 第十八讲:信号量与管程
    • 18.1 信号量
    • 18.2 信号量的使用
    • 18.3 管程
    • 18.4 经典进程同步
      • 18.4.1 生产者-消费者问题
      • 18.4.2 读者-写者问题
      • 18.4.3 哲学家就餐问题
    • 18.5 个人补充:信号量与管程的区别
  • 第十九讲(实验7):同步互斥
    • 19.1 总体介绍
    • 19.2 底层支撑
    • 19.3 信号量设计实现
    • 19.4 管程和条件变量设计与实现(难且重要)
    • 19.5 哲学家就餐问题(管程实现)
  • 第二十讲:死锁和进程通信
    • 20.1 死锁概念
    • 20.2 死锁处理方法
    • 20.3 银行家算法
    • 20.4 死锁检测
    • 20.5 进程通信
    • 20.6 信号和管道
    • 20.7 消息队列和共享内存

第十七讲:同步互斥

17.1 背景

  • 并发进程的正确性
    在这里插入图片描述
  • 进程并发执行的好处

在这里插入图片描述

  • 并发中的错误情况举例
    在这里插入图片描述
  • 原子操作
    在这里插入图片描述
    需要在并发执行的同时,保证一些操作是原子的!!!

17.2 现实生活中的同步问题

  • 买面包举例
    …略,见视频:现实生活中的同步问题

  • 进程的交互关系
    在这里插入图片描述
    关注表中第二行,进程间资源共享带来的问题
    互斥:一个进程占用资源,其他进程不能使用;
    死锁:多个进程各占用部分资源,形成循环等待;
    饥饿:其他进程可能轮流占用资源,而某个进程可能一直得不到资源(比如优先级过低的进程)

17.3 临界区及同步实现方式

17.3.1 临界区

  • 临界区
    在这里插入图片描述
    临界区:进程访问临界资源(这个资源必须是多个进程共享的)的一段互斥执行的代码,每个进程有自己的临界区
    进入区:检查可否进入临界区的条件对应的代码(如可进入,设置正在访问临界区标志);
    退出区:清除“正在访问临界区”的标志;
    剩余区:进程剩下的代码,与同步互斥无关…

  • 临界区的访问规则
    空闲则入:没有进程在临界区时,任何进程可进入;
    忙则等待:有进程在其临界区时,其他进程不能进入临界区;
    有限等待:等待进入临界区的进程不能无限等待;
    让权等待(可选)不能进入临界区的进程,需要释放CPU(如进入阻塞状态)

17.3.2 禁用硬件中断实现同步

  • 禁止硬件中断
    在这里插入图片描述
  • 缺点
    在这里插入图片描述
    仅在不得不用的时候才使用关中断

17.3.3 基于软件的同步

  • 软件同步原理
    => 在进程的进入区和退出区修改共享变量来实现同步
    在这里插入图片描述
  • 方法一:不可行
    在这里插入图片描述
  • 方法二:不可行
    不满足忙则等待 => 可能两个进程同时判断flag[i]/flag[j],结果两个都满足,同时进入临界区!
    在这里插入图片描述
  • 方法三:不可行
    不满足空闲则入 => 可能两个进程同时修改flag[i]/flag[j],结果循环判断时,两个进程都不能进入临界区!
    在这里插入图片描述
  • Peterson算法
    在这里插入图片描述
  • Dekkers算法
    可扩展到多个进程
    在这里插入图片描述
  • N进程的软件同步方法
    在这里插入图片描述
  • 基于软件的同步方法分析
    复杂:需要多个进程间共享数据项
    需要忙等待:浪费CPU时间

17.3.4 高级抽象的同步方法(锁)

  • 概述
    在这里插入图片描述

  • 锁是一个抽象的数据结构
    用一个二进制变量表示锁定/解锁,它的内部基于原子操作指令
    Lock::Acquire()
    锁被释放前其他进程一直处于等待状态,Acquire返回后某个得到锁;
    Lock::Release()
    释放锁,唤醒任何等待该锁的进程;
    在这里插入图片描述
  • 原子操作指令
    重点关注:TS指令和exchange指令
    在这里插入图片描述
    在这里插入图片描述
  • 使用TS指令实现自旋锁(spinlock)
    在这里插入图片描述
  • TS指令实现无忙等待锁
    通过交换指令也可以实现
    在这里插入图片描述
  • 基于原子操作指令的锁的特征
    对比:中断禁用只适用于一个处理机(关中断只能禁止当前处理机?)
    在这里插入图片描述
    在这里插入图片描述

第十八讲:信号量与管程

18.1 信号量

  • 回顾 & 概述
    在这里插入图片描述
    信号量与管程属于 => 高层次的编程抽象
    在这里插入图片描述
    信号量与锁是并列的高层抽象
    在这里插入图片描述

  • 信号量
    信号量与软件同步的区别
    软件同步:各进程间是平等的,他们遵守同一个规则进行同步,没有仲裁者;
    信号量同步:此时操作系统是作为一个仲裁者!
    在这里插入图片描述
    在这里插入图片描述

  • 信号量的特性
    在这里插入图片描述
    自旋锁不能实现先进先出 => 它没有组织需要资源的进程进行排队。锁释放后,哪个进程请求锁,则能先获得资源。

  • 信号量的实现
    信号量的P、V操作由操作系统来保证原子性
    在这里插入图片描述

18.2 信号量的使用

  • 信号量分类
    在这里插入图片描述
    互斥可以理解为特殊的同步

  • 信号量实现临界区的互斥访问
    使用二进制信号量
    在这里插入图片描述

  • 信号量实现条件同步
    使用资源信号量
    在这里插入图片描述

  • 存在困难
    在这里插入图片描述
    只有在写程序时尽量避免死锁,执行过程中无法处理死锁问题!

  • 例:生产者-消费者问题
    见18.4.1

18.3 管程

  • 回顾 & 概述
    在这里插入图片描述
    在这里插入图片描述

  • 管程
    在这里插入图片描述
    管程可中途放弃,而临界区方法不能中途退出临界区

  • 管程的组成(4个部分)
    如下面的图中所示,管程主要由四个部分组成:1.共享变量; 2.条件变量; 3.并发执行的进程代码; 4.初始化共享变量的代码
    在这里插入图片描述

  • 条件变量
    在这里插入图片描述

  • 条件变量的实现
    类似于信号量
    在这里插入图片描述

  • 例:管程解决生产者-消费者问题
    见18.4.1

  • 管程条件变量的释放处理方式
    在这里插入图片描述
    前者少了一个切换,更加高效;后者从优先级来说更加合理;
    以生产者-消费者为例,对应代码实现(对比18.4.1):
    在这里插入图片描述

18.4 经典进程同步

18.4.1 生产者-消费者问题

  • 问题描述
    在这里插入图片描述
  • 问题分析
    在这里插入图片描述
  • 代码实现:信号量方式
    在这里插入图片描述
    P、V操作不能交换,且必须先检查空/满,然后再申请和占用缓冲区
  • 代码实现:管程方式
    与信号量方式相比:
    信号量必须将互斥访问紧挨着临界区(即mutex->P、V);
    管程却可以将互斥操作直接放在管程代码的外部(lock->Acquire);
    这是因为管程可以中途退出,而信号量确不能中途退出临界区!!!
    在这里插入图片描述

18.4.2 读者-写者问题

  • 问题描述
    在这里插入图片描述

  • 信号量解决读者-写者问题
    在这里插入图片描述
    在这里插入图片描述
    优先策略
    在这里插入图片描述

  • 管程解决读者-写者问题
    在这里插入图片描述
    解决方案:读者
    (写者优先)
    在这里插入图片描述
    解决方案:写者
    (写者优先)
    在这里插入图片描述

18.4.3 哲学家就餐问题

  • 问题描述
    在这里插入图片描述

  • 方案1
    在这里插入图片描述

  • 方案2
    在这里插入图片描述

  • 方案3
    在这里插入图片描述

18.5 个人补充:信号量与管程的区别

  • 管程是为了解决信号量在临界区的PV操作上的配对的麻烦,把配对的PV操作集中在一起管理的方法,它使用了条件变量

第十九讲(实验7):同步互斥

19.1 总体介绍

在这里插入图片描述

19.2 底层支撑

  • 定时器
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 屏蔽中断
    在这里插入图片描述
    在这里插入图片描述
  • 等待队列
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

19.3 信号量设计实现

  • 信号量原理
    在这里插入图片描述
    以P操作为例:
    在这里插入图片描述
    上面是sem的更改,由于关中断保证互斥性;下面是阻塞进程的代码,同样需要关中断
    在这里插入图片描述
    在ucore中,sem信号量的互斥性是由关中断机制保证的!

19.4 管程和条件变量设计与实现(难且重要)

  • 管程的定义
    管程包含的内容:1共享变量、2条件变量、3并发执行的进程代码、4初始化共享数据的代码
    在这里插入图片描述

  • 管程的数据结构
    在这里插入图片描述

  • 管程的实现
    在这里插入图片描述

  • 条件变量的定义
    条件变量看起来与信号量几乎一样,但是在实现上有很大的不同
    在这里插入图片描述
    在这里插入图片描述
    由图可知,条件变量直接使用了信号量!

  • 条件变量的signal和wait操作
    图中,上部分是原理,下部分是实现 => 可见,二者是有差异的!
    在这里插入图片描述
    在这里插入图片描述

  • 管程和信号量的设计与实现
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 条件变量wait、signal原理与实现的对比
    1.关于等待信号量的进程数量
    在这里插入图片描述
    2.关于等待队列
    在这里插入图片描述
    3.关于管程中互斥信号量的释放
    在这里插入图片描述
    与之对应的其实在另一个管程中,如下:
    在这里插入图片描述
    4.关于管程中互斥信号量的释放
    在这里插入图片描述
    在这里插入图片描述

  • 管程中互斥信号量不会导致死锁和重入
    在这里插入图片描述

  • 执行过程分析
    在这里插入图片描述

19.5 哲学家就餐问题(管程实现)

  • 管程定义和初始化
    在这里插入图片描述
  • 哲学家线程
    在这里插入图片描述
  • 哲学家线程调用的管程操作
    注意它类似于信号量,但是不同于信号量,主要区别就是下面标红的部分!
    在这里插入图片描述

第二十讲:死锁和进程通信

20.1 死锁概念

  • 死锁示例
    在这里插入图片描述

  • 进程访问资源的流程
    在这里插入图片描述

  • 资源分类
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 资源分配图
    在这里插入图片描述
    在这里插入图片描述

  • 死锁的必要条件
    互斥:任何时刻只能有一个进程使用一个资源实例(共享资源不可能死锁);
    持有并等待:进程至少持有一个资源,并且正在等待其他进程持有的资源;
    非抢占:资源只有在使用后自愿放弃,不可剥夺;
    循环等待:等待进程的集合中存在循环

20.2 死锁处理方法

  • 方法概述
    死锁预防与死锁避免的区别
    死锁预防:是设法至少破坏产生死锁的四个必要条件之一,严格的防止死锁的出现
    死锁避免:在系统运行过程中注意避免死锁的最终发生,它不那么严格的限制产生死锁的必要条件的存在,因为即使死锁的必要条件存在,也不一定发生死锁。
    在这里插入图片描述

  • 死锁预防:限制资源申请方式
    在这里插入图片描述
    互斥:把互斥的共享资源封装成可同时使用的资源(互斥在资源内部实现)
    持有并等待:进程请求资源时,要求它不持有任何其他资源;或者仅允许进程在开始执行时间,一次请求所有需要的资源; => 资源利用率低
    非抢占:如果进程请求不能立即分配所有资源,则释放已占有的资源; 只在能够获得所有需要资源时,才执行分配资源操作
    循环等待:对资源排序,要求进程按顺序请求资源

  • 死锁避免
    在这里插入图片描述

  • 安全与死锁
    在这里插入图片描述
    在这里插入图片描述

20.3 银行家算法

  • 银行家算法(死锁避免)
    在这里插入图片描述
  • 数据结构
    在这里插入图片描述
  • 安全状态判断
    基本思路:如果能够找到一个安全序列,对于序列中的每个线程Ti,资源的需求量都小于当前可用的资源数量 => 按照这个序列执行,最终每个线程都能获得需要的资源,从而是安全的!
    在这里插入图片描述
  • 算法描述
    在这里插入图片描述
  • 示例
    …略

20.4 死锁检测

  • 概述
    在这里插入图片描述

  • 数据结构
    在这里插入图片描述

  • 检测算法
    类似于死锁避免中算法的安全判断的算法!
    在这里插入图片描述
    分析算法的时间复杂度可知,开销较大 => 所以操作系统通常不管死锁

  • 示例
    …略

  • 死锁检测算法的使用
    在这里插入图片描述

  • 死锁恢复:进程终止
    终止进程的选择:
    在这里插入图片描述

  • 死锁恢复:资源抢占
    在这里插入图片描述

20.5 进程通信

  • 概述
    在这里插入图片描述
  • 通信方式
    间接通信利用内核,使用消息队列,可以多对多
    直接通信:利用一片共享的内存区域,只能一对进程间通信
    在这里插入图片描述
  • 直接通信
    在这里插入图片描述
  • 间接通信
    在这里插入图片描述
    在这里插入图片描述
  • 阻塞(同步)与非阻塞通信(异步)
    1.阻塞通信方式
    阻塞发送:发送者在发送消息后进入等待,知道接受者成功收到
    阻塞接收:接收者在请求接受消息后等待,直到成功收到一个消息
    2.非阻塞通信方式
    非阻塞发送:发送者发送消息后,可立即进行其他操作
    非阻塞接收:接收者在请求接收后没有收到任何消息(可能因为没有发送),不用等待,可直接进行其他操作
  • 通信链路缓冲
    在这里插入图片描述

20.6 信号和管道

  • 信号
    信号其实就是一个特定的中断 => 可结合csapp异常控制流理解…
    在这里插入图片描述
  • 信号的实现
    在这里插入图片描述
  • 信号使用示例
    在这里插入图片描述
  • 管道
    1.管道就是多个进程共享的一个内存文件,发送方只需向管道写数据,而不用关心接收方是谁,接收方同理…
    2.管道虽然说是“文件”,但是它不是文件系统/硬盘上的文件,它本质上只是内存中的一个缓冲区
    3.管道是半双工的,数据只能向一个方向流动(仅针对匿名管道);
    4.只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程)(仅针对匿名管道)
    在这里插入图片描述
  • 管道相关的系统调用
    在这里插入图片描述
  • 管道示例
    在这里插入图片描述

20.7 消息队列和共享内存

  • 消息队列
    在这里插入图片描述
  • 消息队列的系统调用
    注意消息队列是独立于创建它的进程,进程结束后,消息队列并不会自动删除,所以需要有单独的控制消息队列的系统调用!
    在这里插入图片描述
  • 共享内存
    在这里插入图片描述
  • 共享内存的实现
    注意:需要由程序员提供同步(比如信号量机制)!!!
    在这里插入图片描述
  • 共享内存的系统调用
    在这里插入图片描述

这篇关于ucore—17至20讲:同步互斥、信号量、死锁、进程通信的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/686246

相关文章

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

服务器集群同步时间手记

1.时间服务器配置(必须root用户) (1)检查ntp是否安装 [root@node1 桌面]# rpm -qa|grep ntpntp-4.2.6p5-10.el6.centos.x86_64fontpackages-filesystem-1.41-1.1.el6.noarchntpdate-4.2.6p5-10.el6.centos.x86_64 (2)修改ntp配置文件 [r

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

[Linux]:进程(下)

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:Linux学习 贝蒂的主页:Betty’s blog 1. 进程终止 1.1 进程退出的场景 进程退出只有以下三种情况: 代码运行完毕,结果正确。代码运行完毕,结果不正确。代码异常终止(进程崩溃)。 1.2 进程退出码 在编程中,我们通常认为main函数是代码的入口,但实际上它只是用户级

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

【C++学习笔记 20】C++中的智能指针

智能指针的功能 在上一篇笔记提到了在栈和堆上创建变量的区别,使用new关键字创建变量时,需要搭配delete关键字销毁变量。而智能指针的作用就是调用new分配内存时,不必自己去调用delete,甚至不用调用new。 智能指针实际上就是对原始指针的包装。 unique_ptr 最简单的智能指针,是一种作用域指针,意思是当指针超出该作用域时,会自动调用delete。它名为unique的原因是这个

vue2 组件通信

props + emits props:用于接收父组件传递给子组件的数据。可以定义期望从父组件接收的数据结构和类型。‘子组件不可更改该数据’emits:用于定义组件可以向父组件发出的事件。这允许父组件监听子组件的事件并作出响应。(比如数据更新) props检查属性 属性名类型描述默认值typeFunction指定 prop 应该是什么类型,如 String, Number, Boolean,

【JavaScript】LeetCode:16-20

文章目录 16 无重复字符的最长字串17 找到字符串中所有字母异位词18 和为K的子数组19 滑动窗口最大值20 最小覆盖字串 16 无重复字符的最长字串 滑动窗口 + 哈希表这里用哈希集合Set()实现。左指针i,右指针j,从头遍历数组,若j指针指向的元素不在set中,则加入该元素,否则更新结果res,删除集合中i指针指向的元素,进入下一轮循环。 /*** @param

java 进程 返回值

实现 Callable 接口 与 Runnable 相比,Callable 可以有返回值,返回值通过 FutureTask 进行封装。 public class MyCallable implements Callable<Integer> {public Integer call() {return 123;}} public static void main(String[] args

C#关闭指定时间段的Excel进程的方法

private DateTime beforeTime;            //Excel启动之前时间          private DateTime afterTime;               //Excel启动之后时间          //举例          beforeTime = DateTime.Now;          Excel.Applicat