![【11. 死锁和进程通信】_第1张图片](http://img.e-com-net.com/image/info8/7fee13d358144a3b87b250d25f7b7b22.jpg)
作者简介: 博主在读机器人研究生,目前研一。对计算机后端感兴趣,喜欢 c + + , g o , p y t h o n , 目前熟悉 c + + , g o 语言,数据库,网络编程,了解分布式等相关内容 \textcolor{orange}{博主在读机器人研究生,目前研一。对计算机后端感兴趣,喜欢c++,go,python,目前熟悉c++,go语言,数据库,网络编程,了解分布式等相关内容} 博主在读机器人研究生,目前研一。对计算机后端感兴趣,喜欢c++,go,python,目前熟悉c++,go语言,数据库,网络编程,了解分布式等相关内容
个人主页: \textcolor{gray}{个人主页:} 个人主页: 小呆鸟_coding
支持 : \textcolor{gray}{支持:} 支持: 如果觉得博主的文章还不错或者您用得到的话,可以免费的关注一下博主,如果三连收藏支持就更好啦 \textcolor{green}{如果觉得博主的文章还不错或者您用得到的话,可以免费的关注一下博主,如果三连收藏支持就更好啦} 如果觉得博主的文章还不错或者您用得到的话,可以免费的关注一下博主,如果三连收藏支持就更好啦 就是给予我最大的支持! \textcolor{green}{就是给予我最大的支持!} 就是给予我最大的支持!
本文摘要
本专栏主要是讲解操作系统的相关知识 本文主要讲解 死锁和进程通信 |
文章目录
- 死锁
-
- 0. 概述
- 1. 死锁问题
- 2. 死锁模型
- 3. 死锁的特征
- 4. 死锁的处理办法
-
- 4.1 死锁预防(约束条件最强)
- 4.2 死锁避免
-
- 4.3 死锁检测
- 4.4 死锁恢复
- 4.5 鸵鸟算法(这是解决死锁用的最多的一种)
- 5. 进程通信(IPC)
-
- 5.0 概述
-
- 5.1 信号
- 5.2 管道
- 5.3 消息队列
- 5.4 共享内存
清华操作系统系列文章:可面试可复习
1. 操作系统—概述
2. 操作系统—中断、异常、系统调用
3. 操作系统—物理内存管理
4. 操作系统—非连续内存分配
5. 虚拟内存管理
6. 操作系统—虚拟内存管理技术页面置换算法
7. 进程管理
8. 调度算法
9. 同步与互斥
10. 信号量和管程
11. 死锁和进程通信
12. 文件系统管理
死锁
0. 概述
1. 死锁问题
![【11. 死锁和进程通信】_第2张图片](http://img.e-com-net.com/image/info8/17df1063347e429d9c0dafad48400ab8.jpg)
- 一组阻塞的进程持有一种资源等待获取另一个进程所占有的一个资源
- 死锁的原因:
- 多进程并发执行,每个进程都需要这个资源,而资源是共享的,所有的进程都可以抢着用。自己拥有资源还抢其他资源,导致谁也执行不了
- 什么是死锁
- 每个进程拥有自己的资源,但是它又要需要其他的资源,而其他的资源被另一个进程占有,而另一个进程又需要前一个进程的资源,导致谁都不释放自己的资源,又想获得其他进程的资源,就导致死锁
- 示例:
- 系统有2个磁带驱动器
- P1和P2各有一个,都需要另外一个**
2. 死锁模型
- 资源类型R1,R2,…,Rm(CPU, memory space, IO devices)
- 每个资源类型Ri有Wi个实例.
- 每个进程使用资源如下:
- require,get ← free resource
- use,hold ← requested,used resource
- release ← free resource
可重复使用的资源(获取资源—>使用资源—>释放资源)
- 在一个时间只能有一个进程使用且不能被删除
- 进程获得资源,后来释放由其他进程重用
- 处理器,IO通道,主和副存储器,设备和数据结构,如文件,数据库和信号量
- 如果每个进程拥有一个资源并请求其他资源,死锁可能发生
使用资源
- 创建和销毁
- 在IO缓存区的中断,信号,消息,信息
- 如果接收消息阻塞可能会发生死锁
- 可能少见的组合事件会引起死锁
资源分配图
P1 --> Rj
表示进程 i 正在使用资源 j
Rj --> Pi
表示资源 j 被进程 i 所使用
![【11. 死锁和进程通信】_第3张图片](http://img.e-com-net.com/image/info8/85e8d883a250439d8e796a017159a789.jpg)
![【11. 死锁和进程通信】_第4张图片](http://img.e-com-net.com/image/info8/c1a5c5e1c2c94f7898c66a6a0edf9884.jpg)
资源分配例子(无死锁)
![【11. 死锁和进程通信】_第5张图片](http://img.e-com-net.com/image/info8/a72776457e8543c7a7efa49ae6ab671a.jpg)
资源分配例子(有死锁)
![【11. 死锁和进程通信】_第6张图片](http://img.e-com-net.com/image/info8/2586694b93d14bec87d39b3c300af7a5.jpg)
有循环的资源分配图没有死锁
![【11. 死锁和进程通信】_第7张图片](http://img.e-com-net.com/image/info8/aa3babec7d064a34bd8be737d0e0ed53.jpg)
总结
- 如果图中不包含循环:
- 如果图中包含循环:
- 如果每个资源类只有一个实例,那么死锁
- 如果每个资源类有几个实例,可能死锁
3. 死锁的特征
死锁的4个必要条件(死锁出现一定会出现以下四个条件,但是出现以下四个条件不一定死锁)
互斥
: 在一个时间只能有一个进程使用资源
持有并等待
: 进程保持至少一个资源正在等待获取其他进程持有的额外资源
无抢占
: 一个资源只能被进程资源释放,进程已经完成了它的任务之后
循环等待
: 存在等待进程集合{P0,P1,...,Pn}
,P0
正在等待P1
所占用的资源,P1
正在等待P2
占用的资源…Pn-1
在等待Pn
的资源,Pn
正在等待P0
所占用的资源
4. 死锁的处理办法
常见方法
- 确保系统永远不会进入死锁状态
- 运行系统进入死锁状态,然后恢复.
- 忽略这个问题,假装系统中从来没有发生死锁,用于大多数操作系统,包括UNIX
4.1 死锁预防(约束条件最强)
就是让死锁不会出现(将死锁出现的某一个条件打破就不会出现死锁了,前面死锁的4个必要条件,有一个条件被打破就不会出现死锁)
限制申请方式
-
互斥 - 共享资源不是必须的,必须占用非共享资源
-
占用并等待 - 必须保证当一个进程请求的资源,它不持有任何其他资源
- 需要进程请求并分配其所有资源,它开始执行之前或允许进程请求资源仅当进程没有资源(我要拿到全部资源而不是一部分资源,当资源不能满足是,我就放弃所有资源)
- 资源利用率低,可能发生饥饿
-
无抢占 -(kill到当前执行的进程)
- 如果进程占有某些资源,并请求其他不能被立即分配的资源,则释放当前正占有的资源
- 被抢占资源添加到资源列表中
- 只有当它能够获得旧的资源以及它请求新的资源,进程可以得到执行
4 循环等待 - 对所有资源类型进行排序(资源都递增或者资源都递减),并要求每个进程按照资源的顺序进行申请
4.2 死锁避免
需要系统具有一些额外的先验信息提供
- 最简单和最有效的模式是要求每个进程声明它可能需要的每个类型资源的
最大数目
- 资源的分配状态是通过限定
提供与分配
的资源数量,和进程的最大需求
- 死锁避免算法
动态检查
的资源分配状态,以确保永远不会有一个环形等待状态
- 当一个进程请求可用资源,系统必须判断立即分配是否能使系统处于安全状态
- 系统处于安全状态指: 针对所有进程,存在安全序列
序列是安全的
: 针对每个Pi,Pi要求的资源能够由当前可用的资源+所有的Pj持有的资源来满足,其中j
- 如果Pi资源的需求不是立即可用,那么Pi可以等到所有Pj完成
- 当Pi完成后,Pi+1可以得到所需要的资源,执行,返回所分配的资源,并终止.
- 用同样的方法,Pi+2,Pi+3和Pn能获得其所需的资源.
![【11. 死锁和进程通信】_第8张图片](http://img.e-com-net.com/image/info8/a227baae2a4f4eafa519fee04d007a48.jpg)
![【11. 死锁和进程通信】_第9张图片](http://img.e-com-net.com/image/info8/bd191c14456a4685bb989a0a81d46a93.jpg)
死锁预防与死锁避免区别
- 死锁预防是设法至少破坏产生死锁的四个必要条件,严格的防止死锁的出现,而死锁避免则不是那么严格的限制产生死锁的必要条件,因为即使死锁的必要条件存在,也不一定发生死锁。死锁避免是在系统运行过程中注意避免死锁的最终法神
4.3.1 银行家算法
- 只要判断出是
unsafe
状态(unsafe
不等于deadlock
),由于deadlock
更复杂,开销更大,所以当判断出unsafe
后就不能让进程获得资源
![【11. 死锁和进程通信】_第10张图片](http://img.e-com-net.com/image/info8/5d1af62e70374ff2b2c1b51b6ed50dd0.jpg)
银行家算法数据结构
![【11. 死锁和进程通信】_第11张图片](http://img.e-com-net.com/image/info8/4cf1d52320854c0caa95480a0aad5bdf.jpg)
找到安全序列的步骤
- 当所有的Finsh为True则找到了安全序列,只要按照这个序列执行就不会出现死锁,当有一个为False就是unsafe。不安全我们就不能把资源分配给发出请求的进程
![【11. 死锁和进程通信】_第12张图片](http://img.e-com-net.com/image/info8/cd71cc9ee98a440a93cebd1fb0d5c216.jpg)
银行家大体思路
![【11. 死锁和进程通信】_第13张图片](http://img.e-com-net.com/image/info8/cf87e4a27061439c84ced11eb3a37830.jpg)
例子
- 在
Need
中找到一个进程(P1,P2,P3,P4)
所需要资源的个数小于Avaliable vector V(0,1,1)
这个值。
P2
满足条件,P2的Finish
变成True
,然后将P2
的资源释放掉,返回到系统中Avaliable
中去
- 此时
Avaliable中
变为6,2,3,继续找下去,直到找到安全序列。
![【11. 死锁和进程通信】_第14张图片](http://img.e-com-net.com/image/info8/79bae31461d84a5c9d6a03575faa959a.jpg)
4.3 死锁检测
死锁避免
是即使没有死锁,如果判断出来有可能不安全就不让程序继续执行
- 死锁检测条件相比避免和预防又宽松了(
允许系统进入死锁状态,当到达一定时候,系统会判断是否是死锁,就启动恢复机制,不是在每次发出请求的时候,而是系统运行中判断
)
方法
![【11. 死锁和进程通信】_第15张图片](http://img.e-com-net.com/image/info8/85648436bc7d4a589e8cbe583a19d52e.jpg)
数据结构
Available
: 长度为M的向量表示每种类型可用资源的数量
Allocation
: 一个n * m矩阵定义了当前分配给各个进程每种类型资源的数量,如果Alocation[i, j] = k, 进程Pi拥有资源Rj的k个实例
Request
: 一个n * m矩阵表示各进程的当前请求.如果Request[i, j] = k,表示进程Pi请求k个资源Pj的实例
死锁检测算法
![【11. 死锁和进程通信】_第16张图片](http://img.e-com-net.com/image/info8/fd72ca6b54da4d1181adcb4634bc171e.jpg)
很少使用算法的原因
- 操作系统中很少使用银行家算法。死锁检测算法的原因是开销比较大
- 对于银行家算法,需要知道每一个进程需要的最大资源个数,这个信息很难获得
俩个例子
- 死锁检测算法与银行家算法是很类似的
![【11. 死锁和进程通信】_第17张图片](http://img.e-com-net.com/image/info8/525ade6f45364cb28c593ad51a45bef5.jpg)
![【11. 死锁和进程通信】_第18张图片](http://img.e-com-net.com/image/info8/a615f5e9e23c431db3321e4b1122b0cd.jpg)
检测算法使用
- 何时,使用什么样的频率来检测依赖于:
- 死锁多久可能会发生?
- 多少进程需要被回滚? one for each disjoint cycle
- 如果检测算法多次被调用,有可能是资源图有多个循环,所以我们无法分辨出多个可能死锁进程中的哪些"造成"死锁### 4.5 死锁恢复(约束条件最弱)
4.4 死锁恢复
- 1. 终止所有的死锁进程
- 2. 在一个时间内终止一个进程直到死锁消除
- 终止进程的顺序应该是(具体应该终止哪 个进程):
- 进程的优先级
- 进程运行了多久以及需要多少时间才能完成
- 进程占用的资源
- 进程完成需要的资源
- 多少进程需要被终止
- 进程是交互还是批处理
- 3. 选择一个受孩子 - 最小的成本
- 4. 回滚 - 返回到一些安全状态,重启进程到安全状态
- 5. 饥饿 - 同一进程可能一直被选作受害者,包括回滚的数量
4.5 鸵鸟算法(这是解决死锁用的最多的一种)
5. 进程通信(IPC)
5.0 概述
- 概述
- 通信模型
- 直接及间接通信
- 阻塞与非阻塞
- 通信链路缓冲
- 信号(与信号量不一样)
- 管道
- 消息队列
- 共享内存
进程通信的原因:保证进程独立的同时,也需要进程之间的沟通
- 进程通信的机制及同步
- 不使用共享变量的进程通信
- IPC facility 提供2个操作:
- send(message) - 消息大小固定或者可变
- receive(message)
- 如果P和Q想通信,需要:
- 在它们之间建立通信链路
- 通过send/recevie交换消息
- 通信链路的实现
- 物理(例如,共享内存,硬件总线)
- 逻辑(例如,逻辑属性)
![【11. 死锁和进程通信】_第19张图片](http://img.e-com-net.com/image/info8/82231b48ad2441aca53cacb56fe7c76f.jpg)
5.0.1 直接通信
- 进程必须正确的命名对方:
- send(P, message) - 发送消息到进程P
- receive(Q, message) - 从进程Q接收信息
- 通信链路的属性
- 自动建立链路
- 一条链路恰好对应一对通信进程
- 每对进程之间只有一个链路存在
- 链路可以是单向的,但通常是双向的
5.0.2 间接通信
-
定向从消息队列接收消息
- 每个消息对垒都有一个唯一的ID
- 只有它们共享了一个消息队列,进程才能够通信
-
通信链路的属性
- 只有进程共享一个共同的消息队列,才建立链路
- 链接可以与许多进程相关联
- 每对进程可以共享多个通信链路
- 链接可以是单向或者双向
-
操作
- 创建一个新的消息队列
- 通过消息队列发送和接收消息
- 销毁消息队列
-
原语的定义如下:
- send(A, message)
- receive(A, message)
-
消息传递可以是阻塞或非阻塞
-
通信链路缓冲
- 将消息缓存起来,缓存的目的就是提高效率,来避免发送发和接收方的不匹配,可能发的很快,接收的很慢,将临时不能处理的数据放在缓存。
-
通信链路缓存大小:
- 0容量 - 0 message : 发送方必须等待接收方
- 有限容量 - n messages的有限长度 : 发送方必须等待,如果队列满
- 无限容量 - 无限长度 : 发送方不需要等待
5.1 信号
硬件中断与软件中断
- 硬件中断:由外设引起的,是指向量中断,即中断源的识别标志,可用来存放中断服务程序入口地址或跳转到中断服务程序入口地址
- 软件中断:执行中断指令引起的, 利用硬件中断的概念,用软件方法模拟,实现宏观上的异步执行效果。
- 信号Signal
- 软件中断通知事件处理
- Examples: SIGFPE, SIGKILL, SIGUSRI, SIGSTOP, SIGCONT
- 接收到信号时会发生什么?
catch
: 指定信号处理函数被调用
ignore
: 依靠操作系统的默认操作(abort, memory dump, suspend or resume process)
mask:
闭塞信号因此不会传送(可能是暂时的,当处理同样类型的信号)
- 不足:
信号实现
![【11. 死锁和进程通信】_第20张图片](http://img.e-com-net.com/image/info8/f563cf50bd414c038ff7e39e92a3cd7f.jpg)
5.2 管道
- 管道是数据交换的,与信号不一样
- 管道是有容量的
- 子进程从父进程继承文件描述符
- 0 stdin, 1 stdout, 2 stderr
- 进程不知道(或不关心)从键盘,文件,程序读取或写入到终端,文件,程序.
例如: $ ls | more (两个进程, 管道是缓存,对于ls来说是stdout,对于more来说是stdin )
![【11. 死锁和进程通信】_第21张图片](http://img.e-com-net.com/image/info8/9dbb200cd278461ba90db231d3c72a36.jpg)
shell:
- 创建管道
- 为ls创建一个进程,设置stdout为管道写端
- 为more创建一个进程,设置为stdin为管道读端
5.3 消息队列
消息队列与管道区别
管道是父进程为子进程建立好的通道(如果没有父子关系,管道就建立不起来,且管道的数据是一个字节流,没有结构化的表示)
消息队列通过多个不相关的进程通过消息队列来传递数据(不需要父子关系,而且是结构化传递)
- 与管道一样有buffersize限制
![【11. 死锁和进程通信】_第22张图片](http://img.e-com-net.com/image/info8/95f3d7fb06c344108ec82699b8cd6b31.jpg)
消息队列按FIFO来管理消息
- message: 作为一个字节序列存储
- message queues: 消息数组
- FIFO & FILO configuration
5.4 共享内存
消息队列与管道都是间接通信方式,而共享内存是直接通信方式(有一个特殊的空间是进程都可以访问到)
管道和消息队列通过系统调用完成通信(send,receive),而共享内存是直接从共享内存读取数据,是最快的,在最开始需要创建一个共享的区域。没有多余的拷贝
- 进程
- 每个进程都有私有地址空间
- 在每个地址空间内,明确地设置了共享内存段
- 优点
- 不足
![【11. 死锁和进程通信】_第23张图片](http://img.e-com-net.com/image/info8/9c0e71295c934cf0aa7d51c464baa394.jpg)
- 将同一块物理内存映射到进程相同或者不同的地址空间中去,当访问不同进程的虚地址时,其实访问的是同一块内存(需要页表等机制支持)