1 死锁问题概述
- 一组阻塞的进程持有一种资源等待获取另一个进程所占有的一个资源.
- 例子: 系统有两个磁带驱动器, P1和P2各有一个, 都需要另外一个.
2 系统模型
资源类型:
,
, ...
, 包括CPU cycles, memory space, I/O devices
每个资源类型有
实例.
每个进程使用资源过程如下:
- request/get <-- free resource
- use/hold <-- requested/used resource
- release <-- free resource
可重复使用的资源:
- 在一个时间只能一个进程使用且不能被删除
- 进程获取资源, 后来释放由其他进程重用
- 处理器, I/O通道, 主和副存储器, 设备和数据结构, 如文件, 数据库和信号量
- 如果每个进程拥有一个资源并请求其它资源, 死锁可能发生
使用资源:
- 创建和销毁
- 在I/O缓冲区的中断. 信号, 消息, 信息
- 如果接收消息阻塞可能会发生死锁
- 可能少见的组合事件会引起死锁
2.1 资源分配图
资源分配图:
一组顶点V和边E的集合:
- V
其中V有两种类型:
, 集合包含系统中所有的进程.
, 集合包含系统中所有的资源类型.
- E
- requesting/claiming edge - directed edge
- assignment/holding edge - directed edge
2.2 资源分配图举例
- 图中有四种类型的资源:
(图中的四个方格),
有一个资源实例可供使用(方格中的小圆),
有两个,
有一个,
有三个
- 图中有三个进程:
(图中的三个大圆圈)
- 有四个资源正在被占用:
中的一个正在被
占用,
中的一个正在被
占用, 另一个正在被
占用,
中的一个正在被
占用
- 有两个资源申请:
申请
,
申请
此时的情况是:
: 正在申请
, 但是
的唯一资源实例被
占用, 等待中
: 正在申请
, 但是
的唯一资源实例被
占用, 等待中
: 正在运行中
并不会出现死锁情况, 因为
使用完
就会释放,
就会拿到
,
使用完
,
,
会对其进行释放,
就会拿到
继续运行, 最终所有进程顺利执行完毕.
如果此时
未使用完
时申请了
, 如图:
此时就会有死锁, 此时有两个环:
通过以上例子可以看出, 当出现死锁情况时, 资源分配图中一定是有环的, 但是资源分配图中有环时并不一定会出现死锁情况, 例子如下:
此时存在环
, 但是并不会出现死锁, 因为
,
并没有依赖, 所以其占用的资源最终会释放, 从而其他进程可以顺利拿到需要的资源并执行.
2.3 基本情况
-
如果资源分配图中不包含循环, 那么就不会出现死锁
-
如果图中包含循环:
- 如果每个资源类只有一个实例, 那么就会死锁
- 如果每个资源类有几个实例, 那么不一定会死锁
3 死锁特征
死锁出现需要以下四个条件:
- 互斥: 在一个时间只能有一个进程使用资源
- 持有并等待: 进程保持至少一个资源正在等待获取其他进程持有的额外资源
- 无抢占: 一个资源只能被进程自愿释放, 进程已经完成了它的任务之后.
- 循环等待: 存在等待进程集合
,
正在等待
所占用的资源,
正在等待
所占用的资源, ...,
正在等待
所占用的资源,
正在等待
所占用的资源.
以上四个条件为死锁出现的必要非充分条件.
4 死锁处理方法
- 确保系统永远不会进入死锁状态
- 运行系统进入死锁状态, 然后恢复
- 忽略这个问题, 假装系统中从来没有发生死锁. 用于大多数操作系统, 包括UNIX.
原因(忽略死锁问题):
- 判断死锁问题出现的开销很大
- 预防死锁会限制操作系统的能力
4.1 Deadlock Prevention
Deadlock Prevention也就是死锁预防. 因为前文讲到, 死锁出现的四个条件为:
- 互斥
- 持有并等待
- 无抢占
- 循环等待
如果有其中一个条件不满足, 死锁也就不会出现.
针对每一个条件的解决方法:
- 互斥: 共享资源不是必须的, 必须占用非共享资源
- 占用并等待: 必须保证当一个进程请求的资源, 它不持有任何其他资源.
- 需要进程请求并分配其所有资源, 它开始执行之前或允许进程请求资源仅当进程没有资源
- 资源利用率低, 可能发生饥饿.
- 无抢占
- 如果进程占有某些资源, 并请求其它不能被立即分配的资源, 则释放当前正占有的资源
- 被抢占的资源添加到资源列表中
- 只有当它获得旧的资源以及它请求新的资源, 进程可以得到执行
- 循环等待: 对所有资源类型进行排序, 并要求每个进程按资源的顺序进行申请
4.2 Deadlock Avoidance
Deadlock Avoidance也就是死锁避免, 需要系统具有一些额外的先验信息提供:
- 最简单和最有效的模式是要求每个进程声明它可能需要的每个类型资源的最大数目
- 资源的分配状态是通过限定提供与分配的资源数量, 和进程的最大需求
- 死锁避免算法动态检查的资源分配状态, 以确保永远不会有一个环形等待状态
当一个进程请求可用资源, 系统必须判断立即分配是否能使系统处于安全状态. 系统处于安全状态指: 针对所有进程, 存在安全序列:
安全状态:
- 序列
是安全的: 针对每个
,
要求的资源能够由当前可用的资源 + 所有的
持有的资源来满足, 其中
.
- 如果
资源的需求不是立即可用, 那么
可以等到所有
完成.
- 当
完成后,
可以得到所需要的资源, 执行, 返回所分配的资源, 并终止.
- 用同样的方法,
,
和
能获得其所需的资源.
如果系统处于安全状态, 那么肯定没有死锁, 如果系统处于不安全状态, 那么可能会死锁. 避免死锁, 也就是确保系统永远不会进入不安全状态, 比如银行家算法.
4.3 Deadlock Detection
Deadlock Detection也就是死锁检测:
- 允许系统进入死锁状态
- 死锁检测算法
- 恢复机制
检测方法:
- 每个资源类型单一实例
把资源分配图简化, 把资源节点都去掉, 只留下进程节点, 如果某一个进程需要一个资源且需要的资源被另一个进程拥有, 那么就直接建立两个进程的连线, 并判断整个图是否有环
- 资源类型的几个实例
1. 与安全判断算法(银行家算法)类似, 设置以下:
: 长度为
的向量表示每种类型可用资源的数量
: 一个
的矩阵定义了当前分配给各个进程每种类型资源的数量
: 一个
矩阵表示各进程的当前请求, 如果
, 表示进程
请求
个资源
的实例.
2. 初始化:
//
为当前空闲资源量
表示线程是否结束
3. 找出这样的索引
:
//线程没有结束的线程, 且此线程将需要的资源量小于当前空闲资源量, 如果没有找到, 跳到第四步
4. 如果找不到可以直接结束的线程, 表示处于死锁状态
算法复杂度:
, 开销较大
检测算法使用时机:
- 依赖于死锁多久可能会发生, 多少进程需要被回滚
- 如果检测算法多次被调用, 有可能是资源图有多个循环, 所以我们无法分辨出多个可能死锁进程中的哪些"造成"死锁
4.4 Recovery from Deadlock
Recovery from Deadlock也就是死锁恢复
如果发现系统有死锁状态, 有以下处理方式:
- 终止所有的死锁进程
- 在一个时间内终止一个进程直到死锁消除
终止进程的顺序应该是:
- 进程的优先级
- 进程运行了多久以及需要多少时间才能完成
- 进程占用的资源
- 进程完成需要的资源
- 多少进程需要被终止
- 进程是交互还是批处理
- 资源抢占
- 选择一个受害者 -- 最小的成本
- 回滚 -- 返回到一些安全状态, 重启进程到安全状态
- 饥饿 -- 同一进程可能一直被选做受害者, 包括回滚的数量