操作系统清华大学版笔记(十一)死锁、银行家算法和进程间通信(直接通信、间接通信)
index
死锁、死锁模型、死锁预防和恢复、银行家算法
- 死锁:一组阻塞的进程(两个或多个),持有一种资源,等待获取另一个进程所占有的资源,而导致谁都无法执行。
由于进程的并发执行引起了死锁。
- 死锁模型
- 资源类型很多,比如CPU cycles , memory space , I/O devices,某个进程运行中的共享变量
- 资源个数可以有n个
- 每个资源类型Ri 有Wi实例
- 每个进程可以怎么使用资源:
-
- request/get ——-free resource
- use/hold ————requested/used resource, other processes cannot get
- release ———–free resource
可重复使用的资源:
-
- 在一个时间只能一个进程使用,且不能被删除。OS避免杀死拥有资源的进程。
- 进程使用资源后要释放,让其他进程重用
- 有物理资源(cpu, I/O通道,主和副存储器),也有抽象的资源(设备和数据结构,如文件,数据库和信号量)
- 如果每个进程拥有一个资源并请求其他资源,可能导致死锁
怎么使用资源?
-
- 创建,销毁—内存管理单元
- I/O缓冲区的中断,信号,消息,信息
- 如果接受信息阻塞可能会发生死锁
- 少见的组合事件可能会引起死锁
如何表述资源的分配?
资源分配图,顶点V和边E的集合
V有两种
P={P1, P2…Pn } 所有进程
R={R1, R2… Rm} 所有资源类型
Requesting/claiming edge –directed edge Pi→Rj
Assignment/holding edge –directed edge Rj→Pi
上图没有死锁,下图死锁,死锁会有闭环出现,可用数据结构的有向图解决
但有闭环出现不一定会死锁,因为资源是循环的
- 如果不包含闭环—>没有死锁
- 如果包括闭环,且每个资源类只有一个实例-→死锁 ;否则,不会。
死锁的特征
死锁的特征 : 四个的必要条件
- 互斥:在一个时间只能有一个进程使用资源
- 持有并等待:进程保持至少一个资源正在等待获取其他进程持有的额外资源
- 无抢占,一个资源只能被进程自愿释放,进程已经完成了它的任务之后
- 循环等待,形成闭环
死锁处理的办法
约束递减
- 死锁预防dead-lock prevention :打破死锁出现的条件
- 互斥—占用非共享资源 会增加不确定性 不推荐
- 占用并等待—保证当一个进程请求资源时,不持有任何其他的资源
-
- all or nothing 需要进程请求并分配其所有资源
- 资源利用率低,可能饥饿
3. 无抢占—允许抢占占有某些资源的进程
4. 循环等待—对所有资源类型进行排序,并要求每个进程按照资源的顺序进行申请,会出现资源利用不够
- 死锁避免 deadlock avoidance :当进程运行过程中,根据申请资源的情况判断会不会死锁,如果会就不给资源。 (需要系统具有一些先验信息)
- 最简单有效就是要求每个进程声明它需要的每个类型资源的最大数目
- 资源在分配中根据最大数目限定提供与分配的资源数目,和进程的最大需求
- 死锁避免算法要动态检查资源的分配状态,来避免出现环形等待。
- 环形等待不一定会死锁。分为安全状态,不安全状态,死锁状态,不安全状态包括死锁。
当一个进程请求可用资源,系统必须判断分配资源是否能让系统处于安全状态。
安全状态:针对所有进程,存在安全的时间序列。第一个P1结束,第二个P2结束。。。都能得到满足,正常结束。则称序列< P1, P2…Pn >是安全的:针对每一个进程Pi,它要求的资源能够由当前可用的资源+所有i之前的进程所持有的资源来满足。
进程会相继结束,Pi只能用它之前的进程的资源。
如果Pi资源的需求不是立即可用,那么Pi可以等到所有Pj完成。
当Pi完成后Pi+1得到所需要的资源,执行,释放资源,并终止。
银行家算法(死锁避免)
DIJ设计的 有多个资源实例 每个进程必须能最大限度地利用资源
一个进程请求一个资源时,不得不等待
所有资源都必须在一段有效时间释放
找到理想执行时序,找到就认为是安全的
安全状态检测:
Finish [i] 得到了所有资源,可以执行结束
看哪个未结束的进程的need小于avaliable,就是第一个结束的进程,结束后释放资源,重复。
例子:
上面是safe的
死锁检测deadlock detection
银行家算法,由于开销大,且需要一开始就知道max[i,j],实际上不一定能得到,所以主要用于开发阶段的调试,不会用于检测,特别是单一OS时
死锁恢复recovery from deadlock
- 通过杀死所有死锁进程,
- 在一个时间内终止一个进程直到死锁消除等方式完成,都干扰了进程的正常运行,都有强制性。
- 终止进程的顺序应该是
- 进程的优先级
- 进程运行了多久及需要多久时间才能完成
- 进程占用的资源
- 进程完成需要的资源
- 多少进程需要被终止
- 进程是交互还是批处理
多数情况下,就是重启。
资源抢占,打破4个条件。
- 以最小的成本选择一个受害者
- 重启进程,返回到安全状态—回滚
- 同一进程可能一直被选为受害者,包括回滚的数量—饥饿
确保不会死锁,运行系统进入死锁然后恢复
假装不知道死锁,不占了就重启(死锁恢复):用于大多数操作系统,包括UNIX,主要是因为开销大,为了避免死锁设定条件会降低OS的性能
11-2 IPC: inter process communication 进程间通信
- 进程通信的机制及同步
- 不使用共享变量的进程通信
- IPC facility 提供2个操作:
- send(message) - 消息大小固定/可变
- receive (message)
- 如果P和Q想通信,需要:
- 在它们之间建立通信链路,
- 通过send/receive交换消息
- 通信链路的实现
- 物理(例如,共享内存,硬件总线)
- 逻辑(如逻辑属性)
进程要相互独立,但另一方面也要相互协作
发送消息,接收消息
左侧进程A和B是间接的通信,右侧是直接通信
- 直接通信
为了实现直接通信,要有发送和接收的ID
进程必须正确地命名对方
send( P, message) - 发送信息到进程P
- 通信链路的属性
自动建立链路
一条链路恰好对应一对通信进程
每对进程之间只有一个链接存在
链接可以是单向的,但通常为双向的
- 间接通信
为了实现间接通信,要发送到共享区,发送方和接收方都不关注具体的另一方是谁
定向从消息队列接收消息:
每个消息队列都有一个唯一的ID
只有他们共享了一个消息队列,进程才能通信
- 通信链路的属性:
只有进程共享一个共同的消息队列,才建立链路
链接可以与许多进程相关联
每对进程可以共享多个通信链路
连接可以是单向或者双向
- 操作:
建立一个新的消息队列
通过消息队列发送和接收消息
销毁消息队列
原语的定义如下:
send(A, message) – 发送消息到队列A
receive(A, message) - 从队列A接受消息
另一方面,消息传递可以分为阻塞,非阻塞
- 阻塞被认为是同步的
blocking send has the sender block until the message is received
blocking receive has the receiver block until a message is available
- 非阻塞被认为是异步的
non-blocking send has the sender send the message and continue
non-blocking receive has the receiver receive a valid message or null
通信链路缓冲:
队列的消息被附加到链路的3种方式
- 0容量—0 messages 发送方必须等待接收方
- 有限容量—n messages 的有限长度,发送方在队列满的时候要等待
- 无限容量—理想状况,不用等
ipc常用手段:信号,管道,消息队列,共享内存
信号: signal
- 硬件中断interrupt,信号是软件中断,通知有事件要处理
- 应用程序会catch,默认,停下来处理信号,特殊处理函数。
- examples: SIGFPE, SIGKILL, SIGUSRI, SIGSTOP, SIGCONT
- 接收到信号时会发生什么
- catch : 指定信号处理函数被调用
- ignore: 依靠操作系统的默认操作 , 如abort, memory dump, suspend or resume process
- mask: 闭塞信号因此不会传送(可能是暂时的,当处理同样类型的信号)
- 不足:不能传输要交换的任何数据
效率很高,异步。一般处理完后会回到被打断的进程。
过程:
第二步,改入口,OS把系统调用返回的堆栈修改到信号处理函数的入口,再把信号处理函数结束后的地址处理成原有进程中断点的入口。
木马程序会改堆栈
管道pipe:间接通信
用于数据交换,与信号不同。理解为内存中的一个buffer
- 子进程从父进程继承包括文件描述符等的资源。File descriptor 0stdin, 1 stdout, 2 stderr
UNIX想灵活组合小程序,一个的输出是另一个的输入,用竖线|来表示
- 把ls的输出stdout重定向,通过一个类似buffer的管道作为stdin传输给more。More以为是从i/o给它的,实际是ls给它的。进程不关心。
完成分页显示目录的功能
管道相当于内存中的一块buffer,buffer是有限的,满了会阻塞,如果ls太慢也会sleep
能协作的基础是有shell,shell会创建一个管道,为ls创建进程,设置stdout为管道写端,对more同理。管道以文件的形式存在。
消息队列: 间接通信
管道必须有父进程,数据是字节流,没有数据结构。消息队列可以多个不相干的进程来传递数据,而且message作为一个字节序列存储,message quenues是消息数组。是一个有意义的结构化。
按FIFO/FILO管理
有Buffer限制
共享内存share memory: 直接通信
不用系统调用send&receive,数据量最大,最快。
开始要创建共享区域。方便,高效,没有多余的拷贝。
每个进程都有私有地址空间,其中明确地设置了共享内存段。同一块物理内存映射到不同的地址空间中去。如页表。。。
但必须同步数据访问。写的时候要上锁。同步互斥。
Linux Unix中常见
Socket机制。