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

第十七讲:同步互斥

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 消息队列和共享内存

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值