不能防止死锁。

Download Report

Transcript 不能防止死锁。

第4章 死锁处理
本章知识点:
4.1 死锁问题概述
 4.2 死锁处理
 4.3 哲学家用餐问题

1
4.1 死锁问题概述
死锁是由于进程间相互竞争系统资源
或通信而引起的一种阻塞现象。如果操作
系统不采取特别的措施,这种阻塞将永远
存在,最终可能导致整个系统处于瘫痪状
态。因此,死锁问题是操作系统中需要考
虑的重要问题。
多线程编程必须特别注意死锁问题,
因为多个线程可能因为竞争共享资源而容
易产生死锁。
2
4.1.1 死锁的形成--可重用资源
下面是一个使用可重用资源而发生死锁的例子。
两个进程P1和P2竞争必须互斥访问的磁盘文件D和磁带
机T,(各一个)程序重复地执行以下操作:
P1
repeat
…
Request(D);
…
Request(T);
…
Release(T);
…
Release(D);
…
forever
P2
repeat
…
Request(T);
…
Request(D);
…
Release(D);
…
Release(T);
…
forever
P1、P2并发执行时,相对速
度无法予知,当出现 P1占用 D
,P2 占用 T 后,P1又请求 T,
但因 T 被 P2 占用,所以 P1 处
于等待状态;这时 P2 执行,它
又请求 D,但 D 已被 P1 占用,
所以 P2 也处于等待资源状态。
它们相互等待对方占用的资源,
致使无法结束这种等待。
3
4.1.2死锁的形成--消耗型资源
下面是使用消耗型资源而发生死锁的例子:
P1
…
Receive(P2,M);
…
Send(P2,N);
P2
…
Receive(P1,Q);
…
Send(P1,R);
如果Receive阻塞就会发生死锁。
4
4.1.3 产生死锁的条件




系统产生死锁有四个必要条件,如果以下四个条
件同时满足,则就会引起死锁:
互斥条件:任一时刻只能有一个进程使用某一资源。
占用并等待条件:一个进程占有至少一个资源,并等
待另一个资源,而该资源为其他进程所占有。
非抢占条件:资源不能被抢占;即只在进程完成任务
后自动释放。
循环等待条件:进程 P1 正在等待资源 x,而 x 被进
程 P2 占有;P2 正等待资源 y,而 y 被 P1 占有。
5
4.1.3 产生死锁的条件


所有四个条件必须同时满足才会出现死锁。
四个条件并不完全独立
• 循环等待条件意味着占有并等待条件
•
分开考虑这些条件是有用的(参见后面
的死锁防止)
6
资源分配图

死锁问题可以用称为系统资源分配图的有向图进
行更为精确地描述。
• 图形方式表示:
• 进程
• 资源
P1
P2
R1
•
•
•
R2
(2 个实例)
• 有向边
• 申请边:从进程外部指向资源。
• 分配边:从资源内部指向进程。
7
资源分配图示例
R1
•
P1
R2
•
P2
•
•
R3
P3
•
•
•
R4
8
资源分配图

如果资源分配图出现环(有循环)

如果每类资源只有一个实例,则定会
死锁。
• 如果每类资源有多个实例,则可能会
死锁。
没有环,就不会死锁。
•
9
资源分配图示例
R1
•
P1
•
P2
•
•
R3
R2
P3
P 2 R 3  P 3  R 2  P 2
cycle, deadlock
10
资源分配图示例
•
•
P1
R1
P3
P2
P 1 R 1  P 3  R 2  P 1
cycle, no deadlock
•
•
P4
11
4.2 死锁处理
为了使系统不发生死锁,必须设法
破坏产生死锁的四个必要条件之一,或者
允许死锁产生,但当死锁发生时能检测
出死锁,并有能力实现恢复。
12
4.2.1 死锁预防
死锁预防是设法至少破坏产生死锁
的必要条件之一,从而消除产生死锁的
任何可能性,严格地防止死锁的出现。
但方法过于保守,对资源限制严格,使
资源利用率和进程执行效率大大降低,
它是以降低处理速度作为代价的。
13
4.2.1 死锁预防
1. 阻止互斥
破坏第一个条件,使资源可以同时访问而不是
互斥使用,这是个简单的方法,但在进程并发执行
的情况下往往有许多资源是不能同时访问的(写操
作),所以这种做法不是都可行的。
• 只能对可共享的资源(如只读文件)这样做。
• 不适合非共享资源,例如、为写而打开的文件,
打印机等。
14
4.2.1 死锁预防
2. 破坏“占用并等待”条件
必须保证:当一个进程申请一个资源时,它不能占有其它
资源。
采用资源的静态预分配策略,一次申请所有的资源。
优点:
简单安全,易于实施;
在进程的活动较单一时性能好;
无须抢占。
缺点:
资源利用率低;
启动进程慢,效率低;
有“饥饿”现象存在。
15
4.2.1 死锁预防
3. 破坏“非抢占”条件(允许抢占)
方法1:若拥有某种资源的进程在申请其他资源时遭到拒绝,则它必
须释放其占用的资源,以后若有必要可再次申请上述资源。
方法2:当一进程申请的资源正被其他进程占用时,可通过操作系统
抢占该资源,此方法在两个进程优先级相同时,不能防止死锁。
优点:
对状态容易保留和恢复的资源较为方便。
缺点:
实现困难,恢复现场代价高;
导致过多的不必要抢占;
易导致循环重启。
16
4.2.1 死锁预防
4. 破坏“循环等待 ”条件
采用资源定序方法,将所有资源按类型线性排队,并按递增规
则编号。进程只能以递增方式申请资源,因而不会导致循环等待。
如果进程申请一个资源,它首先必须释放所有比该资源编号大
的资源。
优点:
资源的申请与分配逐步进行,比预分配策略的资源利用率高;
易实现编译期间的检查;
无须执行时间,在系统设计阶段问题就已解决。
缺点:
严格限制资源的顺序性,不允许增加资源请求;
在使用资源的顺序与系统规定不一致时,资源利用率降低;
不能抢占。
17
死锁预防示例—按序分配破坏循环等待
1: CPU
5: floppy drive
10: printer
P1: 占有 CPU, 可以申请软驱和打印机
P2: 占有软驱,可以申请打印机但不能申请 CPU
P3: 占有软驱和打印机,要申请 CPU 必须先释放
打印机和软驱
18
4.2.2 死锁避免
死锁避免方法并不是严格限制产生
死锁必要条件的存在,只是防止系统进
入不安全状态,从而避免死锁的发生。
死锁避免算法就是避免系统进入不安全
状态的算法。银行家(Banker)算法是
最著名的死锁避免算法。
19
4.2.2 死锁避免


从每个进程预先得到有关该进程需要
资源的信息。
通过仔细的分配资源来避免死锁。
•
•
以便计算机系统总是停留在“安全”
状态。
确保仅仅将以避免死锁的方式分配
资源。
20
4.2.2 死锁避免

如果存在一个安全序列,那么系统处于安全状
态。
• 存在进程顺序 P1、P2、P3、…、 Pn
如果对于每个 Pi , Pi 申请的资源小于当前
可用资源加上所有进程 Pj (其中 j<i)所占
有的资源,那么这一顺序为安全序列。
如果没有这样的顺序存在,那么系统就处于不
安全状态。
•

21
4.2.2 死锁避免
系统: 12 个磁带机,3 个进程
当前可用的: 3 个磁带机
最大需求
P0
P1
P2
10
4
9
当前占有
5
2
2
存在安全序列: P1, P0, P2
所以系统处于安全状态
22
4.2.2 死锁避免



安全 = 不会死锁,不安全 = 可能死锁
死锁 = 不安全
在前面的例子中,从安全状态到不安全状态是可
能的。
• 如果在某个时刻,P2 申请并分配到 1 台磁带机,
那么系统就不再处于安全状态。
• 这时,只有 P1 可以得到其所有的磁带机并运行。
在 P1 执行完成并归还所有它占有的磁带机后,
P0 和 P2 陷入死锁。
• 所以即使进程申请一个当前可用的资源,它可
能仍然必须等待。
23
4.2.2 死锁避免 -资源分配图算法


如果每种资源类型只有一个实例,则资
源分配图的变形可用于死锁避免
增加 需求边 (虚线)
• 需求边 Pi Rj 表示进程 Pi 可能在将
来某个时刻申请资源 Rj。
• 所有需求边必须在任何资源分配前出
现。
24
资源分配图算法
•
•
•
当进程 Pi 申请资源 Rj 时,需求边
变成申请边Pi Rj 。
当一个资源 Rj 被分配时,申请边
变成分配边Rj Pi
当一个资源 Rj 被释放时,分配边
变成需求边Pi Rj
25
资源分配图算法
•
R1
需求边
需求边
P1
P2
需求边
需求边
•
R2
初始状态
26
资源分配图算法

申请处理
•
•
当一个资源被申请时,如果在资源分
配图中转换申请边到分配边没有产生
环,那么申请被准许。
检测图中是否有环的算法需要 n2 级
的操作,其中n 是系统的进程数量。
27
资源分配图算法
•
P1
R1
初始状态
P2
•
R2
28
资源分配图算法
•
P1
R1
序列
•P1 请求 R1
P2
•
R2
29
资源分配图算法
•
P1
R1
序列
•P1请求 R1
•R1 分配给 P1
P2
•
R2
30
资源分配图算法
•
P1
R1
序列
•P1请求 R1
•R1分配给 P1
•P2请求 R2
P2
•
R2
31
资源分配图算法
•
P1
R1
序列
•P1请求 R1
•R1分配给 P1
•P2请求 R2
•R2分配给 P2
P2
•
R2
32
资源分配图算法
•
P1
R1
P2
•
序列
•P1请求 R1
•R1分配给 P1
•P2请求 R2
•R2分配给 P2
•P1请求 R2
•但是必须等待 P2
R2
33
资源分配图算法
•
P1
R1
P2
•
R2
序列
•P1请求 R1
•R1分配给 P1
•P2请求 R2
•R2分配给 P2
•P1请求 R2
•但是必须等待 P2
•P2请求 R1
•因为这将产生环,
所以请求不允许。
34
资源分配图算法
•
P1
R1
P2
•
R2
序列
•P1请求 R1
•R1分配给 P1
•P2请求 R2
•R2分配给 P2
•P1请求 R2
•但是必须等待 P2
•P2请求 R1
•因为这将产生环,
所以请求不允许。
隐藏的死锁
35
4.2.2 死锁避免
1.避免启动新进程
执行一个新进程,当且仅当当前所有
进程和新进程的最大资源需求量之和能被
系统满足时,才能启动一个新的进程。这
个方法并不是最优的,因为它考虑的是最
坏的情况,即所有的进程都使用它们最大
的资源需求量。这会导致很多实际上可以
运行的进程被剥夺了运行的权利 。
36
4.2.2 死锁避免
2.避免分配资源
避免分配资源也称作Banker(银行家)算法。
Banker算法的主要思想:
1.
若进程Pi的申请超过了其申报的最大需求数,则报错;
2.
若进程Pi的申请超过了可用资源数,则Pi必须等待;
3.
系统暂时为进程Pi分配其所需要的资源,修改资源分配
状态;
4.
调用安全算法检查系统当前状态,若导致不安全状态
,则推迟这种分配。
37
4.2.2 死锁避免
优点:
无须抢占;
比死锁预防限制少,允许更多的进程并发执行。
缺点:
必须知道未来的资源请求信息,要预先声明资源的最大
需求量;
进程必须是独立的,其执行顺序不受同步要求的约束;
资源和进程的数目必须固定;
可能导致进程的长时间阻塞。
38
银行家算法


我们可以用下面的安全性算法(银行家算法的
一部分)找出系统是否处于安全状态。
数据结构

available


向量(一维数组),指出当前每种类型资源
可用实例的数量。
max

每个进程对每种资源类型实例的最大需求,
它是 n x m 矩阵(二维数组)
39
银行家算法

allocation



每个进程当前已分配的各种资源类型的
实例数量
它是 n x m 矩阵(二维数组)
need
每个进程还需要的剩余的资源
 它是 n x m 矩阵(二维数组)
 need = max - allocation
(该算法如此命名是因为这一算法可用于银行
系统,以确保银行决不会分配其现金以致使它
不能满足其所有客户的需要。)


40
银行家算法
A B
C
Resource
instances 10 5 7
allocation
A B
process P0 0
P1 2
P2 3
P3 2
P4 0
1
0
0
1
0
max
need
available
C
A B
C
A B
C
A B
0
0
2
1
2
7
3
9
2
4
3
2
2
2
3
7
1
6
0
4
3
2
0
1
1
3 3 2
Allocation0 = (0 1 0)
Allocation1 = (2 0 0)
5
2
0
2
3
4
2
0
1
3
Need0 = (7 4 3)
Need1 = (1 2 2)
C
41
银行家算法

安全性算法
• 向量 Work 是临时的资源使用数组,它初始化为
当前可用的资源数。
• 向量 Finish 是布尔型数组,每个进程一个单元
并初始化为 false。
allocation
0
2
3
2
0
available
3
3
1
0
0
1
0
2
0
0
2
1
2
max
7
3
9
2
4
Work
3
5
2
0
2
3
need
7
1
6
0
4
3
2
2
2
3
3
2
4
2
0
1
3
3
2
0
1
1
Finish
f
f
f
f
f
42
银行家算法

Step 1 (安全性算法) – P190翻译版

find a value of i such that
 Finish[i] = false, and

Needi <= Work
if no such case, go to step 3
consider i = 1 (ie, process P1). (What about i = 0?)


allocation
0
2
3
2
0
P1
available
找到一个需求可以
满足空闲资源的进程
3
3
2
1
0
0
1
0
max
need
0
0
2
1
2
7
3
9
2
4
5
2
0
2
3
3
2
2
2
3
7
1
6
0
4
4
2
0
1
3
Work
3
3
2
Finish
3
2
0
1
1
f
f
f
f
f
43
银行家算法

Step 2

set Work = Work + Allocationi
把该进程当前已分配的资源

set Finish[i] to true
加上空闲资源的计数值

go back to step 1
allocation
P1
available
3 3 2
0
2
3
2
0
1
0
0
1
0
max
need
0
0
2
1
2
7
3
9
2
4
Work
5 3 2
5
2
0
2
3
3
2
2
2
3
(3 3 2) + (2 0 0)
7
1
6
0
4
4
2
0
1
3
3
2
0
1
1
Finish
f T f f f
44
银行家算法

Step 1

find a value of i such that
 Finish[i] = false, and



Needi <= Work
if no such case, go to step 3
consider i = 3 (ie, process P3).
allocation
P3
available
找到一个需求可以
满足空闲资源的进程
3 3 2
0
2
3
2
0
1
0
0
1
0
0
0
2
1
2
Work
max
7
3
9
2
4
5
2
0
2
3
need
3
2
2
2
3
5 3 2
7
1
6
0
4
4
2
0
1
3
3
2
0
1
1
Finish
f T f f f
45
银行家算法

Step 2
把该进程当前已分配的资源

set Work = Work + Allocationi
加上空闲资源的计数值

set Finish[i] to true

go back to step 1
allocation
P3
available
3 3 2
0
2
3
2
0
1
0
0
1
0
max
need
0
0
2
1
2
7
3
9
2
4
Work
7 4 3
5
2
0
2
3
3
2
2
2
3
(5 3 2) + (2 1 1)
7
1
6
0
4
4
2
0
1
3
3
2
0
1
1
Finish
f T f T f
46
银行家算法

step 3
• if Finish[i] = true for all values of i, system is in a
safe state
Finish
•
•
•
T
T
T
T
T
存在一个安全序列: < P1 P3 P4 P2 P0>
如果不都为 true,则存在资源需求不满足
的进程,那么系统处于不安全状态。
还可能有另一个安全序列。只要至少有一
个安全序列,该系统就处于安全状态。
47
银行家算法


现在假定进程 P1 再申请 1个资源类型 A 和 2 个资
源类型 C - 我们可以马上准许这个申请吗?
我们假定这个申请可以满足,就会有如下新状态
allocation
max
need
0
1
0
7
5
3
7
4
3
3
0
2
3
2
2
0
2
0
3
0
2
9
0
2
6
0
0
2
1
1
2
2
2
0
1
1
0
0
2
4
3
3
4
3
1
available
2 3 0
48
银行家算法


我们必须确定这个状态是否安全,为此,
执行安全性算法,并找到一个安全序列:
< P1 P3 P4 P0 P2>
因此,可以立即准许进程 P1的这个申请。
49
死锁检测


如果系统采用了死锁避免或死锁防止,
则死锁检测可以不需要
当死锁发生时,操作系统必须提供:
•
•
一个用来检查系统状态从而确定是否
出现了死锁的算法。
一个用来从死锁状态中恢复的算法
50
4.2.3 死锁检测
基本思想:
在某时刻t,求得系统中各类可利用资源的数目向
量w(t),对于系统中的一组进程{p1,p2 ,…pi ,…pn },
找出那些对各类资源请求数目均小于系统现在所拥有
的各类资源数目的进程。这样的进程能够获得它们所
需要的全部资源并运行结束。当它们运行结束后释放
所占有的全部资源,从而使可用资源数目增加,这样
的进程加入到可运行结束的进程序列L中,然后对剩下
的进程再作上述考查。如果一组进程{p1, p2 ,…pn }中
有几个进程不属于序列L中,那么它们会被死锁。
51
死锁检测

如果每种资源类型只有单个实例,则可
以用等待图(资源分配图的一个变种)
系统必须维护等待图并周期性地在图
中搜索是否出现环
如果每种资源类型有多个实例可用类似
于银行家的算法。
•

52
资源分配图
R1
•
R3
等待图
•
P1
P1
P2
P2
P3
P3
R2
•
应用检测算法

何时调用检测算法,取决于以下两个因素:
 死锁可能发生的频率是多少 – 如果死锁
经常发生,那么就应该经常调用检测算
法。
 当死锁发生时,有多少进程会受影响?
54
4.2.3 死锁检测
优点:
 不会推迟进程的启动;
 在线处理比较便利。
缺点:
 丢失了固有的抢占;
 执行检测算法需要一定的CPU开销。
55
死锁检测


频繁地调用死锁检测算法可能引起相当
的计算开销。
一 种开销较小的方法是在一个不频繁的
时间间隔里调用检测算法。例如 CPU 使
用率低于 40% 时。
56
4.2.4 死锁恢复
一旦检测到死锁,就要有恢复的方
法,恢复死锁的基本方法是剥夺。通常
恢复方法是人工抽去一些作业,释放它
们占有的资源,再重新启动系统。
57
4.2.4死锁恢复


当死锁发生时,谁来处理?
• 操作者,系统管理员
怎样处理?
• 进程终止
 终止一个还是所有的死锁进程?
 如果是一个,选哪个?
 终止的代价是多少?
• 资源抢占
 抢占哪些资源和哪个进程
58
死锁恢复

许多因数都影响着应选择终止哪个进程
 优先级是什么?
 进程已经执行了多久?还要多久?
 进程使用了多少什么类型的资源 (这些资
源是否容易抢占)?
 进程执行完还需要多少资源?
 多少进程需要被终止
 进程是交互式还是批处理的?
59
4.2.5 处理死锁的综合方法



处理死锁的方法有多种,它们各有
优缺点,在不同的环境中使用不同的方
法就比只用一种方法要好得多。
对资源进行分类
对不同类型资源,使用资源定序的方法。
对同一类资源,使用最佳的处理方法。
60
4.3哲学家进餐问题
由 Dijkstra 于 1965 提出并解决。
从那时起,每个发明新的进程同步算法
(原语)的人都希望通过解决哲学家进餐问
题来展示其同步算法的精妙之处。
61
哲学家进餐
•
•
•
•
•
•
•
哲学家要么思考要么吃饭
沉思时不与其他哲学家交流
要吃饭,必须得到两支筷子
 但是每次只能拿一支
 不能用一支筷子吃饭
 吃饭时不思考
不能从其他哲学家手中拿走筷子
当吃完时,放下两支筷子并再次开始思考
五支筷子 代表有限的资源(5个)
五个哲学家 代表(5个)进程
62
哲学家进餐

一种简单的解决方法是每支筷子都用一个信号量来表
示。
• 信号量是一个整型变量,其初值为1。
• 一个哲学家要通过在信号量上执行 wait 操作才能
拿到筷子。
• 一个哲学家要通过在适当的信号量上执行 signal
操作才释放相应的筷子。
• 用信号量方案解决。
Semaphore S1,S2,S3,S4,S5 或
Semaphore chopstick[0..4]
算法见P129
63
哲学家进餐

必须防止死锁

例如,所有的哲学家同时拿
左手边的筷子
必须防止饿死
• 个别哲学家一直吃,即为了
吃而不思考。
•
64
4.3 哲学家用餐问题
哲学家用餐问题是一个死锁和饥饿的典型
问题,也是一大类并发控制所面临的问题。
方法1:每个哲学家先拿其左边的筷子然后再
拿右边的筷子。哲学家用完餐后再将筷子放回
原来的位置。这种解决方法可能导致死锁。
方法2:为避免死锁,可以只允许不超过4个哲
学家同时用餐。这样就至少有一个哲学家可以
得到两根筷子。这个方法可避免死锁和饥饿。
具体算法参见 P130。
65