文章目录
- 一、什么是死锁?
- 死锁产生的原因?
- 死锁产生的必要条件?
- 互斥条件
- 请求并保持
- 不可剥夺
- 环路等待
- 二、处理死锁的基本方法
- 死锁的预防
- 摒弃请求和保持条件
- 摒弃不可剥夺条件
- 摒弃环路等待条件
- 死锁的避免
- 银行家算法案例
提示:以下是本篇文章正文内容,下面案例可供参考
一、什么是死锁?
由于多个进程(两个及以上)竞争共享资源而引起进程不能向前推进的僵死状态被称为死锁。
死锁产生的原因?
进程访问资源按照申请资源、访问资源、释放资源的顺序来执行,如果出现竞争共享资源且分配资源的顺序不当时,则可能会产生死锁。
死锁产生的必要条件?
互斥条件
当一个进程访问某个共享资源时,其他进程不能访问该共享资源。如果当前某个共享资源正在被进程访问,则其他进程想要对该共享资源进行访问时,必须要把请求该共享资源的进程阻塞起来,直到资源被当前所拥有进程释放。
请求并保持
进程已经保持拥有了至少一个资源,又提出了申请新资源的要求,而新申请的资源已经被其他进程所占用,此时进程就会陷入阻塞状态,但又对自己所拥有的资源保持不释放,使得其他进行无法访问该进程所保持的资源。
不可剥夺
进程已经获取的资源不能被其他进程所剥夺,只能由自己释放。
环路等待
在发生死锁时,必然存在一个进程申请资源的环形链,即进程集合{p0,p1,p2,p3…}中,p0等待获取p1占用的一个资源,p1等待获取p2占用的一个资源,p2等待p3…,最总pn等到获取p0所占用资源,此时形成一个环形闭环。
二、处理死锁的基本方法
处理死锁的基本方法有预防死锁、避免死锁、检测并解除死锁、忽略死锁问题等。为确保不发生死锁,操作系统可以采用死锁预防和死锁避免方案。
死锁的预防
死锁的预防是根据死锁的必要条件来进行处理,即当不满足死锁成立的四个必要条件(互斥条件、请求并保持、不可剥夺、环形等待)中的一个,即死锁无法形成。需要明确的是在操作系统中,无法预知进程是否访问某个临界资源,所以通常不能采用摈弃互斥条件
来预防死锁的发生,因此死锁的预防可以从剩下来的三个条件入手。
摒弃请求和保持条件
可以通过摒弃请求和保持条件来预防死锁。摒弃请求和保持条件的一种方法即:
系统要求所有进程一次性地申请在整个运行过程中所需要的全部资源,如果其中存在一个资源申请不成功,则其他资源也不分配给该进程,该进程进入阻塞状态。也就是在运行前将所有需要资源一次性进行申请锁定,后续运行过程中将不再像外部申请其他资源。
摒弃不可剥夺条件
可以通过摒弃不可剥夺条件来预防死锁。摒弃不可剥夺条件即:
一个已保持某些资源的进程,当它再次提出申请新的资源时,如果不能立刻得到满足,必须释放自身所拥有的所有资源。这种方法的缺点是实现复杂、代价高。
摒弃环路等待条件
摒弃环路等待条件即:
进程必须按照规定的顺序申请资源,对所有不同类型的资源进行排序,要求每个进程按照规定顺序申请资源。
缺点:
1.系统为资源分配的顺序可能与进程实际使用资源的顺序不同。
2.在编码实现复杂
死锁的避免
银行家算法是一种避免死锁的资源分配和调度算法,由Edsger Dijkstra 在 1965 年提出。用于操作系统中资源的管理,确保系统不会进入死锁状态。基本思想是通过模拟资源预分配,确保系统在任何时候都能满足至少一个进程所需的最大资源,从而避免死锁。 银行家算法主要包括以下几个步骤:
- 初始资源类型以及数量,并初始化每个进程所需最大资源数量,当前分配资源数量、当前资源可用剩余量。
- 安全性检查:检查当前系统是否存于安全性状态。
- 资源请求:当一个进程请求资源时,首先检查进程请求资源是否超出该进程最大资源数量,如果请求的某个资源大于该进程所需该资源的最大数量,则拒绝请求。否则系统尝试为该进程分配资源,并更新状态是否安全。
银行家算法案例
假设当前存在5个进程,同个需要申请三种不同类型的资源A\B\C,资源A一共有10个,资源B共有5个,资源C共有7个。
- 假设p0进程对资源A\B\C最大需求为7,5,3,当前已经分配A\B\C资源为0,1,0,因此p0进程还需要分配A\B\C资源个数为7,4,3。
- 假设p1进程对资源A\B\C最大需求为3,2,2,当前已经分配A\B\C资源为2,0,0,因此p1进程还需要分配A\B\C资源个数为1,2,2。
- 假设p2进程对资源A\B\C最大需求为9,0,2,当前已经分配A\B\C资源为3,0,2,因此p2进程还需要分配A\B\C资源个数为6,0,0。
- 假设p3进程对资源A\B\C最大需求为2,2,2,当前已经分配A\B\C资源为2,1,1,因此p3进程还需要分配A\B\C资源个数为0,1,1。
- 假设p4进程对资源A\B\C最大需求为4,3,3,当前已经分配A\B\C资源为0,0,2,因此p4进程还需要分配A\B\C资源个数为4,3,1。
这里要记住公式: Need(需求)= Max(所需最大)-Alloc(已经分配);Avail(可用数量)= 总数-Alloc(已经分配)
各资源总数A:10, B:5,C:7.
进程名称 | Alloc(A B C) | Max(A B C) | Need(A B CC) | Avail(A B C) |
---|---|---|---|---|
p0 | 0 1 0 | 7 5 3 | 7 4 3 | |
p1 | 2 0 0 | 3 2 2 | 1 2 2 | |
p2 | 3 0 2 | 9 0 2 | 6 0 0 | |
p3 | 2 1 1 | 2 2 2 | 0 1 1 | |
p4 | 0 0 2 | 4 3 3 | 4 3 1 |
通过Alloc已分配的A、B、C资源进行总和,可以计算出当前A资源已经分配了7个,B类资源已经分配了2个,C类资源已经分配了5个,因此A、B、C资源剩余可分配数量分别为3:3:2。Avail(可用数量)= 总数-Alloc(已经分配)
因此我们可以从p0~p4进行匹配,可以发现p0还需要资源分别为7:4:3,而现在剩余资源3:3:2并不满足条件,因此拒绝向p0分配资源。而p1所需资源1:2:2可以被剩余可分配资源满足,因此尝试将资源分配给进程p1,分配图更新后如下:
进程名称 | Alloc(A B C) | Max(A B C) | Need(A B CC) | Avail(A B C) |
---|---|---|---|---|
p0 | 0 1 0 | 7 5 3 | 7 4 3 | |
p1 | 3 2 2 | 3 2 2 | 0 0 0 | 2 1 0 |
p2 | 3 0 2 | 9 0 2 | 6 0 0 | |
p3 | 2 1 1 | 2 2 2 | 0 1 1 | |
p4 | 0 0 2 | 4 3 3 | 4 3 1 |
当可剩余资源分配给p1进程运行完成后,p1将会把所拥有资源释放,因此A、B、C资源的数量变为 5:3:2。
进程名称 | Alloc(A B C) | Max(A B C) | Need(A B CC) | Avail(A B C) |
---|---|---|---|---|
p0 | 0 1 0 | 7 5 3 | 7 4 3 | |
p1(执行完成) | 0 0 0 | 3 2 2 | 0 0 0 | 5 3 2 |
p2 | 3 0 2 | 9 0 2 | 6 0 0 | |
p3 | 2 1 1 | 2 2 2 | 0 1 1 | |
p4 | 0 0 2 | 4 3 3 | 4 3 1 |
现在再次尝试进行新的一轮分配,p0、p2进程所需资源大于当前可分配资源,因此拒绝分配;而p3进程满足条件,因此尝试将资源分配给进程p3,分配图更新后如下:
进程名称 | Alloc(A B C) | Max(A B C) | Need(A B CC) | Avail(A B C) |
---|---|---|---|---|
p0 | 0 1 0 | 7 5 3 | 7 4 3 | |
p1(执行完成) | 0 0 0 | 3 2 2 | 0 0 0 | |
p2 | 3 0 2 | 9 0 2 | 6 0 0 | |
p3 | 2 2 2 | 2 2 2 | 0 0 0 | 5 2 1 |
p4 | 0 0 2 | 4 3 3 | 4 3 1 |
当可剩余资源分配给p3进程运行完成后,p3将会把所拥有资源释放,因此A、B、C资源的数量变为 7:4:3。
进程名称 | Alloc(A B C) | Max(A B C) | Need(A B CC) | Avail(A B C) |
---|---|---|---|---|
p0 | 0 1 0 | 7 5 3 | 7 4 3 | |
p1(执行完成) | 0 0 0 | 3 2 2 | 0 0 0 | |
p2 | 3 0 2 | 9 0 2 | 6 0 0 | |
p3(执行完成) | 0 0 0 | 2 2 2 | 0 0 0 | 7 4 3 |
p4 | 0 0 2 | 4 3 3 | 4 3 1 |
现在再次尝试进行新的一轮分配,p0进程所需资源恰好等于当前可分配资源,因此尝试将资源分配给进程p0,分配图更新后如下:
进程名称 | Alloc(A B C) | Max(A B C) | Need(A B CC) | Avail(A B C) |
---|---|---|---|---|
p0 | 7 5 3 | 7 5 3 | 7 4 3 | 0 0 0 |
p1(执行完成) | 0 0 0 | 3 2 2 | 0 0 0 | |
p2 | 3 0 2 | 9 0 2 | 6 0 0 | |
p3(执行完成) | 0 0 0 | 2 2 2 | 0 0 0 | |
p4 | 0 0 2 | 4 3 3 | 4 3 1 |
当可剩余资源分配给p0进程运行完成后,p0将会把所拥有资源释放,因此A、B、C资源的数量变为 7:5:3。
进程名称 | Alloc(A B C) | Max(A B C) | Need(A B CC) | Avail(A B C) |
---|---|---|---|---|
p0(执行完成) | 0 0 0 | 7 5 3 | 0 0 0 | 7 5 3 |
p1(执行完成) | 0 0 0 | 3 2 2 | 0 0 0 | |
p2 | 3 0 2 | 9 0 2 | 6 0 0 | |
p3(执行完成) | 0 0 0 | 2 2 2 | 0 0 0 | |
p4 | 0 0 2 | 4 3 3 | 4 3 1 |
现在再次尝试进行新的一轮分配,当前可分配资源满足p2进程所需资源,因此尝试将资源分配给进程p2,分配图更新后如下:
进程名称 | Alloc(A B C) | Max(A B C) | Need(A B CC) | Avail(A B C) |
---|---|---|---|---|
p0(执行完成) | 0 0 0 | 7 5 3 | 0 0 0 | |
p1(执行完成) | 0 0 0 | 3 2 2 | 0 0 0 | |
p2 | 9 0 2 | 9 0 2 | 0 0 0 | 1 5 3 |
p3(执行完成) | 0 0 0 | 2 2 2 | 0 0 0 | |
p4 | 0 0 2 | 4 3 3 | 4 3 1 |
当可剩余资源分配给p2进程运行完成后,p2将会把所拥有资源释放,因此A、B、C资源的数量变为 10:5:5。
进程名称 | Alloc(A B C) | Max(A B C) | Need(A B CC) | Avail(A B C) |
---|---|---|---|---|
p0(执行完成) | 0 0 0 | 7 5 3 | 0 0 0 | |
p1(执行完成) | 0 0 0 | 3 2 2 | 0 0 0 | |
p2(执行完成) | 0 0 0 | 9 0 2 | 0 0 0 | 10 5 5 |
p3(执行完成) | 0 0 0 | 2 2 2 | 0 0 0 | |
p4 | 0 0 2 | 4 3 3 | 4 3 1 |
现在再次尝试进行新的一轮分配,当前可分配资源满足p4进程所需资源,因此尝试将资源分配给进程p4,分配图更新后如下:
进程名称 | Alloc(A B C) | Max(A B C) | Need(A B CC) | Avail(A B C) |
---|---|---|---|---|
p0(执行完成) | 0 0 0 | 7 5 3 | 0 0 0 | |
p1(执行完成) | 0 0 0 | 3 2 2 | 0 0 0 | |
p2(执行完成) | 0 0 0 | 9 0 2 | 0 0 0 | |
p3(执行完成) | 0 0 0 | 2 2 2 | 0 0 0 | |
p4 | 4 3 3 | 4 3 3 | 0 0 0 | 6 2 4 |
当可剩余资源分配给p4进程运行完成后,p4将会把所拥有资源释放,因此A、B、C资源的数量变为 10:5:7。
进程名称 | Alloc(A B C) | Max(A B C) | Need(A B CC) | Avail(A B C) |
---|---|---|---|---|
p0(执行完成) | 0 0 0 | 7 5 3 | 0 0 0 | |
p1(执行完成) | 0 0 0 | 3 2 2 | 0 0 0 | |
p2(执行完成) | 0 0 0 | 9 0 2 | 0 0 0 | |
p3(执行完成) | 0 0 0 | 2 2 2 | 0 0 0 | |
p4(执行完成) | 0 0 0 | 4 3 3 | 0 0 0 | 10 5 7 |
因此资源分配进程顺序可以是P1->P3->P0->P2->P4。