资料来源:《天勤计算机操作系统高分笔记》+《王道计算机操作系统高分笔记》+《计算机操作系统第三版 汤子瀛》
文章目录
- ∗ ∗ 死锁的概念与处理 \color{Brown}**死锁的概念与处理 ∗∗死锁的概念与处理
- 1.1 死锁的概念 \color{ForestGreen}1.1 死锁的概念 1.1死锁的概念
- 1.2 死锁产生的原因和必要条件 \color{ForestGreen}1.2 死锁产生的原因和必要条件 1.2死锁产生的原因和必要条件
- 1.3 处理死锁的基本方法 \color{ForestGreen}1.3 处理死锁的基本方法 1.3处理死锁的基本方法
- 1.4 死锁的预防 \color{ForestGreen}1.4 死锁的预防 1.4死锁的预防
- 1.5 死锁的避免 \color{ForestGreen}1.5 死锁的避免 1.5死锁的避免
- 1.6 死锁的检测与解除 \color{ForestGreen}1.6 死锁的检测与解除 1.6死锁的检测与解除
- 1.7 死锁、饿死、饥饿 \color{ForestGreen}1.7 死锁、饿死、饥饿 1.7死锁、饿死、饥饿
∗ ∗ 死锁的概念与处理 \color{Brown}**死锁的概念与处理 ∗∗死锁的概念与处理
1.1 死锁的概念 \color{ForestGreen}1.1 死锁的概念 1.1死锁的概念
死锁是指多个进程在运行过程中因争夺资源而造成的一种僵局,若无外力作用,这些进程都将无法向前推进。由于每个进程所需的资源都被其他进程占用,彼此都等待对方释放资源,造成所有进程无限期的等待
以下通过两个实例来说明死锁现象:
(1)
(2)在生产者—消费者问题中(具体代码参见《进程同步与互斥》),如果将wait(empty) / wait(full) 与 wait(mutex)的顺序调换,会导致死锁
1.2 死锁产生的原因和必要条件 \color{ForestGreen}1.2 死锁产生的原因和必要条件 1.2死锁产生的原因和必要条件
现代操作系统中,可以将资源分为两类:
(1)可剥夺资源,某进程在获得这类资源后,该资源可被其他进程或系统剥夺。如CPU、主存都属于可剥夺资源(低优先级进程占用CPU可以被高优先级剥夺;系统可以剥夺当前占用主存的进程)
(2)不可剥夺资源,当系统把这类资源分配给某进程后,再也不能强行收回,只能等待该进程用完后自行释放。如磁带机、打印机都属于不可剥夺资源
上述磁带机、打印机都属于永久性资源,即可重复使用。除此之外,系统中还有一类临时资源,它是指由进程产生,并交予其他进程使用,其他进程使用完后便无用的资源(如输入进程传递给计算进程的数据就属于临时资源)
一个资源是否属于可剥夺资源,完全取决于资源本身的性质。对可剥夺资源的竞争不会引起进程死锁,而对不可剥夺资源和临时资源的竞争则有可能导致进程死锁.
死锁产生的原因可归结为以下两点:
(1)竞争资源。对于系统中供多个进程共享的资源,当其数目不足以满足多进程需要时,会引起诸进程对资源的竞争而产生死锁
(2)进程间推进顺序非法。进程在运行过程中,请求和释放资源的顺序不当,也同样会产生进程死锁
虽然资源竞争可能导致死锁,但是资源竞争并不等于死锁,只有当进程的推进顺序不当时,才会导致死锁。
假设系统中有两个供进程P1、P2共享的资源A、B,若两个进程按照如下顺序推进,则必然产生死锁:
进程P1、P2均争夺资源A、B,且它们的推进顺序不当,导致它们分别握有某一资源,同时又申请另一资源,结果就是两个进程均被阻塞无法继续推进,发生死锁。若两个进程按照如下三种方式执行,则可以避免死锁发生:
前两种方式是令进程顺序执行,避免两个进程竞争资源;而后一种则是调整并发进程推进顺序(P2申请B资源时会阻塞,但不会导致死锁)
死锁产生的必要条件有以下4条:
(1)互斥条件:进程所申请的资源具有排他性,即某段时间内仅供一个进程占用
(2)不剥夺条件:进程所获得的资源只有当进程使用完毕时才会被该进程释放,使用期间无法被其他进程剥夺
(3)请求与保持条件:当进程请求新资源不得而被阻塞时,它已占用的资源不会被释放
(4)环路等待条件:死锁发生时,必然存在一个“进程—资源”的环形链,即P0等待P1释放资源、P1等待P2释放资源……Pn等待P0释放资源
1.3 处理死锁的基本方法 \color{ForestGreen}1.3 处理死锁的基本方法 1.3处理死锁的基本方法
目前,用于处理死锁的方法可归结为以下四种:
(1)鸵鸟算法:即认为死锁不可能发生,对死锁不进行任何处理,UNIX、LINUX、Windows等系统均采用该方法,当死锁发生时,用户需要手动重启计算机
(2)预防死锁:通过设置某些限制条件,去破坏产生死锁的四个必要条件中的一个或多个条件,来预防发生死锁。例如采用可剥夺式进程调度,来破坏“不剥夺条件”
(3)避免死锁:在资源的动态分配过程中,用某种方法防止系统进入不安全状态,从而避免死锁的产生。例如当某资源分配有可能产生死锁时,则不进行这种分配
(4)检测与解除死锁:通过系统的检测机构及时检测出死锁的发生,然后采取某种措施解除死锁
其中,预防死锁、避免死锁都属于事先预防策略,即在死锁发生前就采取措施规避或预防其发生;而检测和解除死锁则是事后处理策略,即在死锁发生后再采取措施对其进行解除
需注意区分预防死锁和避免死锁:
预防死锁:无需计算死锁发生的可能性,而是对系统施加严格的限制条件,破坏一个或多个死锁产生的必要条件,但是会削弱系统的并发性
避免死锁:对系统施加的限制条件较为宽松,有利于进程的并发执行,但是需要提前计算死锁发生的可能性,实现较为复杂
1.4 死锁的预防 \color{ForestGreen}1.4 死锁的预防 1.4死锁的预防
预防死锁只需破坏四个必要条件中的不剥夺条件、请求与保持条件、环路等待条件之一即可,而对于互斥条件,由于其受到资源本身固有特性的限制而无法破坏,因此必须遵守(例如打印机只允许多进程互斥地对其访问)
(1)不剥夺条件
破坏不剥夺条件的策略如下:
当进程请求新资源不得而被阻塞时,则必须释放已拥有的全部资源,待以后需要时再重新申请。这就意味着一个进程已占用的资源会被暂时剥夺,从而破坏了不剥夺条件
该策略实现较为复杂,并且释放已获得的资源可能造成前一阶段工作的失效,反复地申请和释放资源会增加系统开销,降低系统吞吐量。因此该策略只能适用于状态易保存和恢复的资源(如CPU的寄存器和内存资源),而不适用于打印机之类的资源(剥夺资源后代价较大)
(2)请求和保持条件
破坏请求和保持条件,可采用预先静态分配方法:
进程在运行前一次性申请所需的全部资源,且只有当这些资源全部满足时,进程才能投入运行。进程在运行过程中,这些资源一直归它所有,也不再申请新的资源。这样就可以保证系统不会发生死锁
这种方式实现简单且安全,但是会严重降低资源利用率,例如某些资源仅在进程运行后期才会用到(如打印机),这样就会造成进程执行的大部分时间内打印机处于闲置状态,而其他等待打印机的进程只能等待,产生“饥饿”现象
(3)环路等待条件
假设我们将系统中每种类型的资源都进行编号(如打印机编号为1、磁带机为2、磁盘为3……),用 Pi 表示占用某类资源的进程(如P2表示占用磁带机的进程),则环路等待条件的示意图如下图(a)所示:
破坏“环路等待条件”,可采用有序资源分配法:
同样将系统中每类资源编号,并规定占用第 i 类资源的进程只能请求 i 后面的资源,不能请求 i 前面的资源(例如,占用磁带机的进程P2只能请求磁盘资源或排在磁盘之后的资源,而不能请求打印机资源)。在这种情况下,占用第n类资源的进程Pn就不能请求第1类资源,从而在整个环路上人为地制造一个缺口,保证死锁不会发生,如上图(b)所示
采用这种方式对资源利用率和系统吞吐量的影响较小,但是也存在以下缺点:
① 由于对各种资源编号后不宜修改,因此限制了新设备的增加
② 假设某进程需要先使用第n类资源,再使用第1类资源。则它只能先请求第1类资源,再请求第n类资源,在使用第n类资源的过程中,第1类资源将被长时间闲置,造成浪费
③ 对资源的按序使用也会增加程序编写的复杂性
1.5 死锁的避免 \color{ForestGreen}1.5 死锁的避免 1.5死锁的避免
相较于死锁预防,死锁的避免施加的限制条件较弱,它的原理是将系统的状态分为安全状态和不安全状态,并令系统始终处于安全状态,以避免死锁的发生
1.5.1. 安全状态和不安全状态 \color{Fuchsia}1.5.1. 安全状态和不安全状态 1.5.1.安全状态和不安全状态
在避免死锁的方法中,允许进程动态地申请资源,系统在进行资源分配之前,先计算资源分配的安全性。倘若此次分配会使系统进入不安全状态,则不进行此次分配
例如,有P1、P2、P3这3个进程共享某一资源,该资源总数为10个,某一时刻,这三个进程已分配资源数和还需资源数如下表所示:
若系统按照 {P1 、P2 、P3} 的次序为各进程分配、回收资源,则P1、P2、P3进程均无法获得足够的资源,全都会停止运行等待,系统会进入不安全状态。若按照 {P2 、P1 、P3} 的次序为各进程分配、回收资源,则每个进程都能顺利完成,系统始终处于安全状态
由此可知,如果系统按照某种分配顺序为每个进程分配资源,能使得每个进程都顺利完成,则称此时的系统状态为安全状态,称该分配顺序为安全序列;如果不能使每个进程都顺利完成,则称此时的系统状态为不安全状态,称该分配顺序为不安全序列
注意:安全序列和不安全序列均不是唯一的,例如上例中,如果将P3还需资源数改为6,则{P2、P1、P3}和{P2、P3、P1}均为安全序列
不安全状态 ≠ 一定会发生死锁,系统进入不安全状态后,只是可能会发生死锁。实际的系统运行过程中,有些进程占有资源但并没有执行完可能会主动放弃资源,从而避免了死锁发生
∗ ∗ 1.5.2 银行家算法 \color{Fuchsia}**1.5.2 银行家算法 ∗∗1.5.2银行家算法
银行家算法是最具代表性的避免死锁算法。一个完整的银行家算法包含银行家算法和安全检查算法两部分,其基本逻辑是:银行家(系统)收到客户(进程)的贷款申请后(资源请求),先计算贷款完成后银行剩余的资金(银行家算法,计算系统剩余资源),并判断这些资金能不能满足储户的全额取款需求(安全检查算法,判断剩余资源能否满足其他进程的最大需求),若无法满足,则拒绝贷款申请,从而避免出现资金流断裂(死锁)
假设系统从共有n个进程、m类资源,银行家算法(狭义)定义了如下数据结构:
(1)系统空闲资源向量Available[m]:含m个元素的一维数组,Available[ i ]表示第 i 类资源当前空闲数
(2)资源总需求矩阵Max[n][m]:n × m的矩阵,Max[ i ][ j ]表示第 i 个进程对第 j 类资源的最大需求数(即 i 进程运行总共需要多少 j 类资源)
(3)已分配资源矩阵Allocation[n][m]:n × m的矩阵,Allocation[ i ][ j ]表示第 i 个进程当前已分配到的 j 类资源数目
(4)剩余需求矩阵Need[n][m]:n × m的矩阵,Need[ i ][ j ]表示第 i 个进程还需要多少 j 类资源
显然,上面的各向量应满足 N e e d [ i ] [ 0... m − 1 ] = M a x [ i ] [ 0... m − 1 ] − A l l o c a t i o n [ i ] [ 0... m − 1 ] Need[i][0...m-1] = Max[i][0...m-1] - Allocation[i][0...m-1] Need[i][0...m−1]=Max[i][0...m−1]−Allocation[i][0...m−1],且进程 i i i 想立即获得全部剩余需求至少应满足 N e e d [ i ] [ 0... m − 1 ] ≤ A v a i l a b l e [ 0... m − 1 ] Need[i][0...m-1] \leq Available[0...m-1] Need[i][0...m−1]≤Available[0...m−1]
银行家算法描述如下:
设
R
e
q
u
e
s
t
i
Request_i
Requesti为第
i
i
i 个进程的请求向量,
R
e
q
u
e
s
t
i
[
j
]
Request_i[ j ]
Requesti[j] = K 表示
i
i
i 进程向系统请求 K 个
j
j
j 类型资源,当资源请求发出后,系统按如下流程检查:
实现过程如下:
if(Request[i][0...m-1] <= Need[i][0...m-1]){ //先判断i进程请求的资源数有没有超过它的实际需求,如果超过,则请求非法
if(Request[i][0...m-1] <= Available[0...m-1]){ //再判断当前空闲的各类资源能否满足i进程的请求,如果不能,i进程需等待
Avaiable[0...m-1] -= Request[i][0...m-1]; //修改各类资源空闲数目
Allocation[i][0...m-1] += Request[i][0...m-1]; //修改i进程已分配到各类资源数
Need[i][0...m-1] -= Request[i][0...m-1]; //修改i进程还需各类资源数
}
else WAIT;
}
else ERROR;
以上步骤只是对 i i i 进程进行分配试探,系统接下来会对上述修改过的向量执行安全性算法,若安全性算法判断此次分配后系统处于安全状态,则为 i i i 进程正式分配资源;若安全性算法判断此次分配后系统处于不安全状态,则此次分配试探作废,各向量恢复为原来的值, i i i 进程需等待
安全性算法描述如下:
设置工作向量Work[m],含m个元素的一维数组,表示系统当前空闲的各类资源数,初值为Work = Available(此处的Available已经被银行家算法修改过)
设置向量Finish[n],含n个元素的一维数组,表示若将Work内剩余的各类资源分给 i i i 进程,它能否顺利执行完成。其初值为Finish[ i ] = false
安全性算法按如下流程判断:
实现过程如下:
Work[0...m-1] = Available[0...m-1]; //初始化工作向量Work,其初值与Available向量相等
Finish[0...n-1] = false; //初始化所有的进程状态为未完成
while(true) {
在n个进程中找到某个进程i,使得其满足下列条件;
if(Finish[i] == false && Need[i][0...m-1] <= Work[0...m-1]){ //该进程状态为未完成,且系统当前空闲的各类资源数能满足该进程全部所需
模拟该进程的资源分配;
Allocation[i][0...m-1] += Need[i][0...m-1]; //修改该进程已分配的各类资源数
Work[0...m-1] -= Need[i][0...m-1]; //修改系统当前空闲的各类资源数
模拟该进程运行完成,并释放其占用的各类资源;
Work[0...m-1] += Allocation[i][0...m-1]; //修改系统当前空闲的各类资源数
Finish[i] = true; //修改进程状态为可顺利执行完成
}
else if(Fnish[0...n-1])
return SAFE; //若所有进程都能顺利执行完成,则返回安全状态
else
return UNSAFE; //否则,返回不安全状态
}
∗ ∗ 1.5.3 银行家算法示例 \color{Fuchsia}**1.5.3 银行家算法示例 ∗∗1.5.3银行家算法示例
假设系统中有R1、R2、R3三种资源,供P1、P2、P3、P4四个进程共享,它们的初始数量分别为9、3、6,T0时刻的资源分配情况如下表所示
(1)判断T0时刻是否安全
对T0时刻的资源分配情况进行安全性算法分析,若系统按 {P2 、P3 、P1 、P4} 的顺序为各进程分配、回收资源,系统将处于安全状态,因此T0时刻存在安全序列 {P2 、P3 、P1 、P4}
(2)若T0时刻后,进程P2发出资源请求
R
e
q
u
e
s
t
2
Request_2
Request2(1, 0, 1),系统能否将资源分配给它
P2进程发出资源请求 R e q u e s t 2 Request_2 Request2后,系统按照银行家算法,对其进行检查:
①
R
e
q
u
e
s
t
2
Request_2
Request2(1, 0, 1) ≤
N
e
e
d
2
Need_2
Need2(1, 0, 2),为真
②
R
e
q
u
e
s
t
2
Request_2
Request2(1, 0, 1) ≤ Available(1, 1, 2),为真
③ 系统为P2进程进行资源预分配,修改Available、
N
e
e
d
2
Need_2
Need2、
A
l
l
o
c
a
t
i
o
n
2
Allocation_2
Allocation2向量,形成如下表所示的资源变化情况
然后对修改后的资源分配情况进行安全性算法分析,可以找到安全序列{P2、P3、P1、P4},系统按此序列为各进程分配、回收资源,系统将处于安全状态
安全性算法返回“安全”,银行家算法正式为P2执行资源分配(1, 0, 1)
(3)在进程P2申请资源后,若P3发出资源请求 R e q u e s t 3 Request_3 Request3(0, 0, 1),系统能否将资源分配给它
P3进程发出资源请求 R e q u e s t 3 Request_3 Request3后,系统按照银行家算法,对其进行检查:
①
R
e
q
u
e
s
t
3
Request_3
Request3(0, 0, 1) ≤
N
e
e
d
3
Need_3
Need3(1, 0, 3),为真
②
R
e
q
u
e
s
t
3
Request_3
Request3(0, 0, 1) ≤ Available(0, 1, 1),为真
③ 系统为P3进程进行资源预分配,修改Available、
N
e
e
d
3
Need_3
Need3、
A
l
l
o
c
a
t
i
o
n
3
Allocation_3
Allocation3向量,形成如下表所示的资源变化情况
然后对修改后的资源分配情况进行安全性算法分析,但此时空闲资源Available(0, 1, 0)已经不能满足任何进程的需求,故安全性算法返回“不安全”,银行家算法撤销此次的资源预分配,各向量恢复原来的值,进程P3等待
1.6 死锁的检测与解除 \color{ForestGreen}1.6 死锁的检测与解除 1.6死锁的检测与解除
与死锁预防和死锁避免不同,死锁的检测和解除是在死锁发生之后进行的,死锁的检测需要满足以下两点:
(1)保存有关资源的请求和分配信息;
(2)提供一种算法,以利用这些信息来检测系统是否已进入死锁状态
为此需要引入一种数据结构来描述系统资源的分配,这种数据结构称为资源分配图(Resource Allocation Graph,简称RAG)
1.6.1 资源分配图 \color{Fuchsia}1.6.1 资源分配图 1.6.1资源分配图
资源分配图是一种有向图,其定义为RAG = (V, E),其中V是顶点集合、E是有向边集合
顶点集合分为两类:进程顶点 P i ( i = 1 、 2 、 . . . 、 n ) P_i (i = 1、2、...、n) Pi(i=1、2、...、n)、资源类顶点 r i ( i = 1 、 2 、 . . . 、 n ) r_i (i = 1、2、...、n) ri(i=1、2、...、n),进程顶点用圆圈表示,资源顶点用矩形表示(矩形内的圆表示系统中该资源的总数)
有向边集合也分为两类:<
P
i
P_i
Pi,
r
i
r_i
ri>(称为申请边,资源类顶点为弧头)、<
r
i
r_i
ri,
P
i
P_i
Pi>(称为分配边,进程顶点为弧头),前者表示
P
i
P_i
Pi请求一个
r
i
r_i
ri资源,后者表示已分配一个
r
i
r_i
ri资源给
P
i
P_i
Pi
例如上图所示的一个资源分配图,表示进程
P
1
P_1
P1已分配到两个
r
1
r_1
r1资源,并申请一个
r
2
r_2
r2资源;进程
P
2
P_2
P2已分配到一个
r
1
r_1
r1资源和一个
r
2
r_2
r2资源,并申请一个
r
1
r_1
r1资源。但是由于
r
1
r_1
r1资源总数为3,均已分配出去,因此
P
2
P_2
P2只能阻塞,等待空闲的
r
1
r_1
r1资源
1.6.2 死锁定理 \color{Fuchsia}1.6.2 死锁定理 1.6.2死锁定理
可以利用将RAG简化的方法,来检测系统处于S状态时是否为死锁状态,其步骤如下:
(1)在RAG中,找到一个存在连接边(非孤立)、并且资源申请数小于等于空闲资源数(不阻塞)的进程,为该进程分配所需资源,使其顺利执行完成,并释放所占用资源(即删去该进程的连接边),使之成为孤立的结点。如下图(a)所示,
P
1
P_1
P1满足非孤立且不阻塞,
P
2
P_2
P2因阻塞不满足,故删除与
P
1
P_1
P1连接的各边,形成图(b)
(2)进程释放所占资源后,能唤醒其它因等待资源而阻塞的进程。然后再按照第(1)步中的简化方法对剩余的RAG进行简化,得到图©
(3)重复上述步骤。若能消去所有图中所有的边,使所有进程成为孤立结点,则称该图是可以完全简化的;若通过任何过程均不能使该图完全简化,则称该图是不可完全简化的
需注意,不同的简化顺序将得到相同的不可简化图。由此,便可得出死锁定理:系统状态S为死锁状态 ⇔ \Leftrightarrow ⇔ S状态的资源分配图不可完全简化
1.6.3 死锁检测算法 \color{Fuchsia}1.6.3 死锁检测算法 1.6.3死锁检测算法
死锁检测算法采用了与银行家算法(广义)类似的数据结构:
(1)系统空闲资源向量Available[m],表示系统中每类资源的空闲数目
(2)已分配资源矩阵Allocation[n][m],表示每个进程已分配到的各类资源数目
(3)请求向量Request[n][m],表示每个进程请求的各类资源数目
(4)工作向量Work[m],表示系统中每类资源的空闲数目,其初值为Work = Available
(5)表L,用于存储孤立的进程(即
A
l
l
o
c
a
t
i
o
n
i
Allocation_i
Allocationi = 0、
R
e
q
u
e
s
t
i
Request_i
Requesti = 0)
其工作流程与安全检查算法基本一致,只是前者用于死锁检测,后者用于避免死锁:
实现过程如下:
Work[0...m-1] = Available[0...m-1]; //初始化Work向量
for(i = 1; i <= n; i++){ //遍历所有进程,找到已存在的孤立进程,并插入表L
if(Allocation[i][0...m-1] == {0, 0, 0, ..., 0} && Request[i][0...m-1] == {0, 0, 0, ..., 0})
Insert(L, i);
}
while(true){
找到一个满足下列条件的进程i;
if(!Find(L, i) && Request[i][0...m-1] <= Work[0...m-1]){ //该进程未在L表中,且系统中各类资源空闲数能满足该进程的请求
假定为该进程分配其申请的资源,该进程便可执行完成,释放所占资源;
Work[0...m-1] += Allocation[i][0...m-1]; //该进程释放资源
Insert(L, i); //将该进程插入到L表中
}
else if(conclude(L, n))
return normal; //如果所有进程都已入表L,则未处于死锁状态
else
return deadlock; //反之,则系统发生死锁,需要得到处理
}
1.6.4 死锁解除 \color{Fuchsia}1.6.4 死锁解除 1.6.4死锁解除
一旦死锁检测算法检测到系统发生了死锁,就应使陷入死锁的进程从死锁状态中解脱出来,即死锁解除。常用的死锁解除方法有以下三种:
(1)剥夺资源,从其他进程中剥夺足够的资源给死锁进程,以解除其死锁状态
(2)撤销进程,按某种顺序逐个地撤销进程,直到有足够的资源可用,使死锁状态消除为止
(3)进程回退,让一个或多个进程回退(系统需要保存进程的历史信息,设置还原点),直到可以回避死锁发生为止。进程回退时会自愿释放资源,而不是被剥夺
1.7 死锁、饿死、饥饿 \color{ForestGreen}1.7 死锁、饿死、饥饿 1.7死锁、饿死、饥饿
在一个动态系统中,如果操作系统需要为每类系统资源确定一个公平的分配策略,那么可以保证每个申请进程能够在一个有限时间内获得所需资源
如果资源分配策略是不公平的,那么就可能会出现某些进程长时间等待,以至于影响进程推进和响应,此时就发生了进程饥饿。如果进程饥饿到一定程度,进程所赋予的任务即使完成也不再具有实际意义,称该进程饿死
例如在短作业优先调度算法中,如果短作业源源不断地被提交,那么长作业就会被无限期推迟,造成进程饥饿,直到最终该进程饿死
此外,还有一个概念称为活锁,它是指两个或以上进程互相谦让资源(例如互斥实现方法中的“双标志后检查”法会导致这种情况发生),结果造成谁也无法向前推进的情况。与死锁不同,活锁有可能不靠外力作用自行解开
假设我们以一座单车道桥为共享资源,以汽车为进程,每辆汽车都需要在有限时间内通过桥梁到桥对面处理一件急事(进程任务)。则死锁、饥饿、饿死、活锁的关系如下图所示
死锁与饿死均是由于竞争资源而引起的,但两者有以下几种主要差别:
(1)死锁进程处于等待状态;而饿死进程可能处于就绪状态或运行状态(例如短进程优先调度中,长进程已经处于就绪队列,倘若一直没有分配到处理器,那么该进程就是在就绪状态下饿死;倘若该进程在任务有效时间结束后才分配到处理器,那么它就是在执行状态被饿死)
(2)死锁进程等待的资源在无外力作用下永远不会被释放;饿死进程等待的资源会被释放但是不会分配给自己
(3)死锁一定发生了循环等待;饿死进程则不然。因此通过简化资源分配图可以检测死锁是否发生,但是却无法检测是否有进程饿死
(4)死锁一定涉及两个及以上进程;饿死可能只有一个进程