操作系统课程笔记:CPU管理 — 死锁

目录

死锁概念

基本概念

必要条件

互斥条件

持有并等待条件

不可剥夺条件

环路等待条件

处理死锁的四种方法

预防死锁 — 破坏必要条件

互斥条件不能被破坏

破坏“请求和保持”条件

破坏“不可抢占”条件

破坏“循环等待”条件

避免策略

为什么提出避免策略?

(不)安全状态

基本概念

安全状态举例

银行家算法 — 判断资源申请是否可以允许

数据结构

算法的描述

算法核心:安全状态检测

银行家算法举例1

安全性检查

假设 P1 申请 [1, 0, 2]

银行家算法举例2

检测/解除策略

死锁的检测

资源分配图(Resource Allocation Graph)

死锁定理 — 化简资源分配图

死锁的充分必要条件 — 完全化简的资源分配图中有环

死锁检测时机

“死锁检测”与银行家算法中“安全状态检测”有 何联系和区别?

课堂练习

死锁的解除

思考题


死锁概念

基本概念

一组进程处于死锁状态,如果它们中每个 进程都在等待只有组内其他进程才能引发的事件

在多线程编程中,为了防止多线程竞争共享资源而导致数据错乱,都会在操作共享资源之前加上互斥锁,只有成功获得到锁的线程,才能操作共享资源,获取不到锁的线程就只能等待,直到锁被释放。

那么,当两个线程为了保护两个不同的共享资源而使用了两个互斥锁,那么这两个互斥锁应用不当的时候,可能会造成两个线程都在等待对方释放锁,在没有外力的作用下,这些线程会一直相互等待,就没办法继续运行,这种情况就是发生了死锁

必要条件

只有同时满足以下四个条件才会发生:

  • 互斥条件
    • 资源只能由一个进程使用
  • 持有并等待条件;
    • 需要其他资源时不(完全)释放自己的资源
  • 不可剥夺条件
    • 只能由自己主动释放
  • 环路等待条件
    • 可以找到一个进程-资源的循环链

互斥条件

互斥条件是指多个线程不能同时使用同一个资源

比如下图,如果线程 A 已经持有的资源,不能再同时被线程 B 持有,如果线程 B 请求获取线程 A 已经占用的资源,那线程 B 只能等待,直到线程 A 释放了资源。

持有并等待条件

持有并等待条件是指,当线程 A 已经持有了资源 1,又想申请资源 2,而资源 2 已经被线程 C 持有了,所以线程 A 就会处于等待状态,但是线程 A 在等待资源 2 的同时并不会释放自己已经持有的资源 1

不可剥夺条件

不可剥夺条件是指,当线程已经持有了资源 ,在自己使用完之前不能被其他线程获取,线程 B 如果也想使用此资源,则只能在线程 A 使用完并释放后才能获取。

环路等待条件

环路等待条件指的是,在死锁发生的时候,两个线程获取资源的顺序构成了环形链

比如,线程 A 已经持有资源 2,而想请求资源 1, 线程 B 已经获取了资源 1,而想请求资源 2,这就形成资源请求等待的环形图。

处理死锁的四种方法

  1. 预防死锁
  2. 避免死锁
  3. 检测死锁
  4. 解除死锁

预防死锁 — 破坏必要条件

互斥条件不能被破坏

破坏“请求和保持”条件

破坏“不可抢占”条件

破坏“循环等待”条件

避免策略

为什么提出避免策略?

(不)安全状态

基本概念

  • 已知每个进程请求的资源的数量的最大值
  • 一个状态称为安全状态当且仅当存在一个安全序列 (P_1, P_2, ..., P_n)使得
    • 对于任意进程(P_i),(P_i)处于请求的最大资源数不超过系统剩余的资源加上所有在(P_i)前有的资源(j<=i)
  • 注意
    • 可找到一个资源的序列即可
    • 如果不能找到此序列,则为不安全状态

安全状态举例

银行家算法 — 判断资源申请是否可以允许

  • 目标:判断资源申请是否可以允许
  • 核心思想:尝试分配,检测是否是安全状态
数据结构
  • 为了实现银行家算法,设置这样四个数据结构,分别用来描述系统中
    • 可利用的资源
    • 所有进程对资源的最大需求
    • 系统中的资源分配
    • 所有进程还需要多少资源的情况
  • 可利用资源向量 Available
    • 是一个含有 m 个元素的数组,Available[j] = k 表示系统中现有 Rj 类资源 k 个。
  • 最大需求矩阵 Max
    • 是一个 n * m 的矩阵,Max[i, j] = k 表示进程 i 需要 Rj 类资源的最大数目为 k
  • 分配矩阵 Allocation
    • 是一个 n * m 的矩阵,如果 Allocation[i, j] = k 表示进程 i 当前已分得 Rj 类资源的数目为 k
  • 需求矩阵 Need
    • 即为 Max - Allocation
算法的描述

Request_i 是进程 Pi 的请求向量,如果 Request_i[j] = K,表示进程 Pi 需要 KRj 类资源。当 Pi 发出资源请求后,系统按下述步骤进行检查:

  1. 如果 Request_i[j] <= Need[i, j],便转向步骤(2);否则认为出错,因为它所需要的资源数已超过它所宣布的最大值。
  2. 如果 Request_i[j] <= Available[j],便转向步骤(3);否则,表示尚无足够资源Pi 须等待。
  3. 系统试探着把资源分配给进程 Pi,并修改下面数据结构中的数值
    1. Available[j] = Available[j] - Request_i[j]
    2. Allocation[i, j] = Allocation[i, j] + Request_i[j]
    3. Need[i, j] = Need[i, j] - Request_i[j]
  1. 系统执行安全性检测,检查此次资源分配后系统是否处于安全状态
    1. 若安全,才正式将资源分配给进程 Pi,以完成本次分配;
    2. 否则,将本次的试探分配作废,恢复原来的资源分配状态,让进程 Pi 等待。
算法核心:安全状态检测
  1. 设置两个向量:
    • Work: 系统当前资源数目Work = Available
    • Finish: 进程是否顺利运行结束Finish[i] = false
  1. 寻找到一个能满足下述条件的进程 i
    • Finish[i] = false; Need[i, j] <= Work[j]
  1. 如找到,则:
    • Finish[i] = true; Work[j] = Work[j] + Allocation[i, j]
    • 继续执行2.
  1. 所有进程均已结束,则安全;否则不安全
银行家算法举例1

最大需求(Max)和已分配资源(Allocation)

进程

Max

Allocation

Need = Max - Allocation

P0

7 5 3

0 1 0

7 4 3

P1

3 2 2

2 0 0

1 2 2

P2

9 0 2

3 0 2

6 0 0

P3

2 2 2

2 1 1

0 1 1

P4

4 3 3

0 0 2

4 3 1

安全性检查
  1. 初始化
    • Work = Available = [3, 3, 2]
    • Finish = [False, False, False, False, False]
  1. 检查哪个进程可以满足当前的需求
    • P1的需求 [1, 2, 2] 小于等于 Work [3, 3, 2],因此可以分配资源给 P1。
  1. 分配资源给 P1 并更新 Work 和 Finish
    • Work = Work + Allocation[P1] = [3, 3, 2] + [2, 0, 0] = [5, 3, 2]
    • Finish[P1] = True
    • Finish = [False, True, False, False, False]
  1. 继续检查其他进程
    • P3的需求 [0, 1, 1] 小于等于 Work [5, 3, 2],因此可以分配资源给 P3。
    • Work = Work + Allocation[P3] = [5, 3, 2] + [2, 1, 1] = [7, 4, 3]
    • Finish[P3] = True
    • Finish = [False, True, False, True, False]
  1. 继续检查其他进程
    • P0的需求 [7, 4, 3] 小于等于 Work [7, 4, 3],因此可以分配资源给 P0。
    • Work = Work + Allocation[P0] = [7, 4, 3] + [0, 1, 0] = [7, 5, 3]
    • Finish[P0] = True
    • Finish = [True, True, False, True, False]
  1. 继续检查其他进程
    • P2的需求 [6, 0, 0] 小于等于 Work [7, 5, 3],因此可以分配资源给 P2。
    • Work = Work + Allocation[P2] = [7, 5, 3] + [3, 0, 2] = [10, 5, 5]
    • Finish[P2] = True
    • Finish = [True, True, True, True, False]
  1. 继续检查其他进程
    • P4的需求 [4, 3, 1] 小于等于 Work [10, 5, 5],因此可以分配资源给 P4。
    • Work = Work + Allocation[P4] = [10, 5, 5] + [0, 0, 2] = [10, 5, 7]
    • Finish[P4] = True
    • Finish = [True, True, True, True, True]
  1. 最终检查
    • 所有进程的 Finish 均为 True,因此当前状态是安全的。
假设 P1 申请 [1, 0, 2]
  1. 检查需求是否满足
    • P1的需求 [1, 0, 2] <= Need[P1] [1, 2, 2],满足条件。
    • P1的需求 [1, 0, 2] <= Available [3, 3, 2],满足条件。
  1. 试探分配资源给 P1
    • Available = Available - Request = [3, 3, 2] - [1, 0, 2] = [2, 3, 0]
    • Allocation[P1] = Allocation[P1] + Request = [2, 0, 0] + [1, 0, 2] = [3, 0, 2]
    • Need[P1] = Need[P1] - Request = [1, 2, 2] - [1, 0, 2] = [0, 2, 0]
  1. 安全性检查
    • Work = Available = [2, 3, 0]
    • Finish = [False, False, False, False, False]
  1. 继续检查
    • P1的需求 [0, 2, 0] <= Work [2, 3, 0],满足条件。
    • Work = Work + Allocation[P1] = [2, 3, 0] + [3, 0, 2] = [5, 3, 2]
    • Finish[P1] = True
    • Finish = [False, True, False, False, False]
  1. 继续检查
    • P3的需求 [0, 1, 1] <= Work [5, 3, 2],满足条件。
    • Work = Work + Allocation[P3] = [5, 3, 2] + [2, 1, 1] = [7, 4, 3]
    • Finish[P3] = True
    • Finish = [False, True, False, True, False]
  1. 继续检查
    • P0的需求 [7, 4, 3] <= Work [7, 4, 3],满足条件。
    • Work = Work + Allocation[P0] = [7, 4, 3] + [0, 1, 0] = [7, 5, 3]
    • Finish[P0] = True
    • Finish = [True, True, False, True, False]
  1. 继续检查
    • P2的需求 [6, 0, 0] <= Work [7, 5, 3],满足条件。
    • Work = Work + Allocation[P2] = [7, 5, 3] + [3, 0, 2] = [10, 5, 5]
    • Finish[P2] = True
    • Finish = [True, True, True, True, False]
  1. 继续检查
    • P4的需求 [4, 3, 1] <= Work [10, 5, 5],满足条件。
    • Work = Work + Allocation[P4] = [10, 5, 5] + [0, 0, 2] = [10, 5, 7]
    • Finish[P4] = True
    • Finish = [True, True, True, True, True]
  • 当前状态是安全的。
  • P1可以申请[1, 0, 2],并且之后P0可以申请[0, 2, 0]。
银行家算法举例2

检测/解除策略

死锁的检测

资源分配图(Resource Allocation Graph)

  • 进程表示为圆圈节点
  • 资源类型表示为方块节点;其中每个点表示一个实例
  • 请求表示为从进程到资源类型的有向边
  • 分配表示为从资源实例到进程的有向边

有环是死锁的必要条件

有环不是充分条件

死锁定理 — 化简资源分配图

  1. 在资源分配图中,找出一个既不阻塞又非独立的进程结点Pi。在顺利的情况下,Pi可获得所需资源而继续运行, 直至运行完毕,再释放其所占有的全部资源,这相当于消去Pi的请求边和分配边使之成为孤立的结点
  2. Pi释放资源后,便可使Pj获得资源而继续运行,直至Pj完成后又释放出它所占有的全部资源,即将Pj的所有请求边和分配边消去
  3. 在进行一系列的简化后
    1. 若能消去图中所有的边使所有的进程结点都成为孤立结点,则称该图是可完全简化的;
    2. 若不能通过任何过程使该图完全简化,则称该图是不可完全简化的。

死锁的充分必要条件 — 完全化简的资源分配图中有环

死锁检测时机

  • 当进程由于资源请求不满足而等待时,检测死锁
  • 定时检测
  • 有进程在等待,但系统资源利用率下降时检测

“死锁检测”与银行家算法中“安全状态检测”有 何联系和区别?

  • 死锁是不安全状态的最终目的
  • 思想是相同的

课堂练习

死锁的解除

  • 剥夺资源
    • 从其它进程剥夺足够数量的资源给死锁的进程,以解除死锁
  • 撤消进程
    • 撤销全部死锁进程
    • 或者按照某种顺序逐个地撤消进程,直至有足够的资源可用,死锁状态消除为止
    • 有一些优化策略,如为解除死锁状态所需要撤消的进程数目最小;或者撤消进程所付出的代价最小

思考题

考虑由4个相同类型资源组成的系统,系统中有3 个进程,每个进程最多需要2个资源,该系统是否会发生死锁?为什么?

假设系统由相同类型的m个资源组成,有n个进程 ,每个进程至少请求一个资源,且单个进程请求 资源总数不大于m。证明:当n个进程最多需要的资源数之和小于m+n时,该系统无死锁

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值