死锁
死锁的原理
- 死锁是指多个进程因竞争资源而造成相互等待的现象
- 死锁问题没有有效的通用解决方案
- 可重用资源:
- 定义: 一次仅供一个进程安全使用且不因使用而耗尽的资源
处理器
、I/O通道
、内存
、外存
、数据库
、信号量
‘
- 考虑相互竞争的两个进程都要独占访问磁盘文件
D
和磁盘设备T
的情形,此时,多道程序设计系统交替地执行两个进程时就会发生死锁: p 0 p 1 q 0 q 1 p 2 q 2 p_0p_1q_0q_1p_2q_2 p0p1q0q1p2q2
- 可消耗资源:
- 定义: 可被创建(生产)和销毁(消耗)的资源
中断
、信号
、消息
、I/O缓冲区
- 资源分配图:
死锁的条件
- 必要条件:
互斥条件:
一个进程访问共享资源时,其他进程无法再访问该资源,直到正在访问的进程结束了对该共享资源的访问请求和保持条件:
进程在获得一定的资源后,又对其他共享资源发出请求,而该资源被其他进程占有,请求进程被阻塞,并且该进程不释放自己已经占有的资源不可剥夺条件:
进程已经获得的资源,除非完成对共享资源的访问后自己释放,否则不可被剥夺循环等待条件:
存在一个闭合的进程链,每个进程至少占有此链中下一个进程所需的一个资源
- 系统中存在循环等待的进程集合,不一定会发生死锁
死锁的处理
- 死锁的预防: 采用某种策略来消除条件1~4中的某个条件的出现
- 死锁的避免: 基于资源分配的当前状态做动态选择
- 死锁的检测: 检测死锁(满足条件1~4)的存在并从死锁中恢复
死锁预防
- 设计一种系统来排除发生死锁的可能性
- 死锁的预防方法会造成系统资源的低效使用和进程的低效执行
- 分类:
(1)直接死锁预防:
防止三个必要条件中的任何一个条件的发生
(2)间接死锁预防:
防止循环等待的发生
互斥条件
不可能禁止,如果需要对资源进行互斥访问,那么操作系统就必须支持互斥- 为了预防
占有和请求条件
可要求进程一次性请求所有需要的资源,并阻塞这个进程直到所有请求都同时满足
(1)进程可能会被长时间阻塞
(2)为某一进程分配的资源可能未被使用,但其他进程也无法使用该资源
(3)无法预测进程在执行过程中所需的全部资源- 预防
不可剥夺条件
的方法:
(1)占有某些资源的一个进程进一步申请资源时若被拒绝,该进程主动放弃其最初占有的资源,必要时可再次申请这些资源和其他资源
(2) 一个进程请求当前被另一个进程占有的一个资源时,操作系统可以抢占另一个进程,要求它释放资源
(3)后一种方案只有在任意两个进程的优先级都不同的条件下才能预防死锁循环等待条件
可以通过定义资源类型的线性顺序来预防,即若一个进程已分配了 R R R类型的资源,则其接下来请求的资源只能是那些排在 R R R类型之后的资源
(1)类似占有和请求条件
,循环等待的预防方法可能是低效的,它会使进程执行速度变慢
- 死锁预防的方法都会导致低效的资源使用和低效的进程执行
死锁避免
- 死锁的避免允许
互斥条件
、保持和请求条件
以及不可剥夺条件
,但通过明智的选择,可确保永远不会到达死锁点- 和死锁预防相比,死锁避免可允许更多的并发
- 是否允许当前的资源分配请求是通过判断该请求是否可能导致死锁来决定的,因此死锁避免需要知道未来进程资源请求的情况
- 基本方法:
- 若一个进程的请求会导致死锁,则不启动该进程
- 若一个进程增加的资源请求会导致死锁,则不允许这一资源分配
进程启动拒绝
- 考虑一个有 n n n个进程,和 m m m种不同类型资源的系统:
- 矩阵 C l a i m Claim Claim表示每个进程对每种资源的最大需求,其中每一行表示一个进程对所有类型资源的请求,该矩阵信息必须由进程事先声明
(1) R j = V j + ∑ i = 1 N A i j R_j = V_j + \sum_{i=1}^N A_{ij} Rj=Vj+∑i=1NAij,对所有 j j j。所有进程要么可用,要么已被分配
(2) C i j ≤ R i C_{ij} \leq R_i Cij≤Ri,对所有 i , j i, j i,j。任何一个进程对任何一种资源的请求都不能超过系统中这种资源的总量
(3) A i j ≤ C i j A_{ij} \leq C_{ij} Aij≤Cij,对所有 i , j i, j i,j。分配给任何一个进程的任何一种资源都不会差偶偶这个进程最初声明的此资源的最大请求量。- 若一个新进程的资源需求会导致死锁,则拒绝启动这个新进程。仅当:
R j ≤ C ( n + 1 ) j + ∑ i = 1 N C i j , 对 所 有 j R_j \leq C_{(n+1)j} + \sum_{i=1}^N C_{ij}, 对所有j Rj≤C(n+1)j+i=1∑NCij,对所有j
时才启用一个进程 P n + 1 P_{n+1} Pn+1
资源分配拒绝(银行家算法
)
- 安全状态: 至少有一个资源分配序列不会导致死锁(即所有进程都能运行直到结束),否则即为不安全状态
- 基本思想:
- 死锁避免策略能确保系统中的进程和资源总处于安全状态:进程请求一组资源时,假设同意该请求,因此改变了系统的状态,然后确定结果是否仍然处于安全状态,如果是,同一这个请求;如果不是,阻塞该进程直到同一该请求后系统状态仍然是安全的
- 死锁避免策略并不能确切地预测死锁,它仅是预料死锁的可能性并确保永远不会出现这种可能性。
- 死锁避免的特点:
- 缺点:
- 必须事先声明每个进程请求的最大资源,且分配的资源数目必须是固定的
- 进程必须是无关的,即进程间的执行顺序必须没有任何同步要求的限制
- 占有资源时进程不能退出
- 优点:
- 无须死锁预防中的抢占和回滚进程,且与死锁预防相比限制较少
死锁检测
- 死锁检测不限制资源的访问或约束进程的行为,只要可能就会给进程分配所请求的资源
- 操作系统通过周期性的执行一个算法来检测循环等待条件来判断是否发生死锁
- 死锁检测算法:
- 死锁检测可以频繁地在每个资源请求发生时进行,也可以进行得少一些
- 每次进程资源请求时执行死锁检测:
(1)算法简单,且可以尽早检测出死锁情况
(2)频繁地检测会耗费大量的处理器时间
- 死锁检测常见算法:
- 使用 A l l o c a t i o n Allocation Allocation矩阵和 A v a i l a b l e Available Available向量,此外还定义了一个请求矩阵 Q Q Q,其中 Q i j Q_{ij} Qij表示进程 i i i请求的 j j j类资源的数量
- 该算法主要是一个标记未死锁进程的过程,最初,所有进程都是未标记的,然后执行下列步骤:
(1)标记 A l l o c a t i o n Allocation Allocation矩阵中一行全为零的进程
(2)初始化一个临时向量 W W W,令 W W W等于 A v a i l a b l e Available Available向量
(3)查找下标 i i i,使进程 i i i当前未标记且 Q Q Q的第 i i i行小于等于 W W W,即对所有的 1 ≤ k ≤ m , Q i k ≤ W k 1 \leq k \leq m, Q_{ik} \leq W_k 1≤k≤m,Qik≤Wk,若找不到这样的行,终止算法
(4)若找到这样的行,标记进程 i i i,并把 A l l o c a t i o n Allocation Allocation矩阵中的相应行加到 W W W中,即对所有的 1 ≤ k ≤ m 1 \leq k \leq m 1≤k≤m, 令 W k = W k + A i k W_k = W_k + A_{ik} Wk=Wk+Aik。返回步骤3。- 当且仅当这个算法的最终结果有未标记的进程时,才存在死锁,每个未标记的集成都是死锁的
- 该算法不能保证防止死锁,是否死锁取决于将来同意请求的次序,它所做的一切是确定当前是否存在死锁
死锁恢复
- 取消所有的死锁进程
- 死锁进程回滚到某个检查点并重启所有进程
- 连续取消死锁进程直到不再存在死锁,所选取消进程的顺序应基于某种最小代价原则
- 连续抢占资源直到不再存在死锁,需要选择一种基于代价的选择方法
哲学家就餐
- 问题描述:
- 有5个哲学家,他们的生活方式是交替地进行思考和进餐
- 哲学家们共用一张圆桌,分辨坐在周围的5张椅子上
- 圆桌中间放有一大碗面条,每个哲学家分别有一个盘子和一支叉子
- 若果哲学家想吃面条,则必须拿到靠其最近的最优两支叉子。
- 进餐完毕,放下叉子继续思考
- 要求:
- 设计一个合理的算法,是全部哲学家都能进餐(非同时)。
- 算法必须避免死锁和饥饿,哲学家互斥共享叉子
- 基于信号量的解决方案:
- 考虑增加一位服务员,她只允许4位哲学家同时进入餐厅,由于最多有4位哲学家就座,因而至少有有一位哲学家可以拿到两把叉子
- 基于管程的解决方案: