目录
一、什么是死锁
所谓死锁是指多个并发进程,各自持有资源又都等待别的进程释放所拥有的资源,在未改变这种状态之前不能向前推进,这种状态称为死锁,死锁产生的根本原因是系统资源不足。
二、死锁的必要条件
- 互斥:并发进程要求和占用的资源只能被一个进程使用
- 不可抢占:进程已经获得的资源,在未使用完成前,不可被剥夺
- 占有并等待:进程申请并等待新资源的过程中,继续占有已分配的资源
- 循环等待:若干进程形成首尾相接的循环链,循环等待上一个进程的资源
死锁发生时必然会具备这四个必要条件,但这四个条件发生并不代表一定会发生死锁,即这四个条件是死锁的必要条件,但并不是充分条件。
三、死锁的处理方法
1、死锁预防
前面介绍了死锁发生时的四个必要条件,只要破坏这四个必要条件中的任意一个条件,死锁就不会发生。死锁的预防是保证系统不进入死锁状态的一种策略。它的基本思想是要求进程申请资源时遵循某种协议,从而打破产生死锁的四个必要条件中的一个或几个,保证系统不会进入死锁状态。
- 互斥
- 打破互斥条件,即允许进程同时访问某些资源。一般来说,互斥条件不能禁止,有的资源是不允许被同时访问的,像打印机等等,这是由资源本身的属性所决定的。
- 占有并等待
- 为了预防占用并等待的条件,可以要求进程一次性请求所有需要的资源,并阻塞这个进程直到所有请求都满足,可以操作为:进程在开始执行前一次性申请所有需要的资源。如果某个进程所需的全部资源得不到满足,则不分配任何资源,此进程暂不运行。只有当系统能够满足当前进程的全部资源需求时,才一次性地将所申请的资源全部分配给该进程,就能够保证进程开始后一定能执行到结束,不会发生占有资源又申请资源的现象,因此不会发生死锁。
- 缺点:
- 低效性
- 一个进程可能被阻塞很长时间,以等待满足其所有的资源请求。而实际上,只要有一部分资源,它就可以继续执行;
- 分配给一个进程的资源可能会在相当长的一段时间内不会被该进程使用,且不能被其他进程使用,资源利用率低。
- 进程可能事先并不知道它所需要的所有资源
- 低效性
- 不可抢占
- 预防不可抢占的方法有几种
- 占有某些资源的一个进程,在进一步申请资源时如果被拒绝,则该进程必须释放其最初占有的资源,必要时可再次申请这些资源和其他资源
- 一个进程请求当前被另一个进程占用的一个资源时,操作系统可以抢占另一个进程,要求它释放资源。只有在任意两个进程的优先级都不同的条件下,这种方法才能预防死锁。
- 预防不可抢占的方法有几种
- 循环等待
- 可以对不同资源类型进行排序,按照循序进行申请。若进程已经分配了R类型的资源,则接下来请求的资源只能是那些排在R类型之后的资源
- 正确性证明:给每种资源类型指定一个下标,当i<j时,资源Ri排在资源Rj的前面。现在两个进程A和B死锁,原因是A获得Ri并请求Rj,而B获得Rj并请求Ri,那么这个条件是不可能的,因为这意味着i<j且j<i。
- 缺点:类似于占有并等待的预防方法,效率较低,会使进程执行速度变慢。可能在资源Ri的级别排序靠前,需要先于其他资源进行申请,但事实上只会在进程快结束时才会需要使用资源Ri,会造成浪费。
2、死锁避免
利用额外的先验信息,在分配资源时判断是否会出现死锁,只在不会出现死锁时分配资源。
死锁避免方法
- 如果一个进程的请求会导致死锁,则不启动此进程
- 如果一个进程增加资源的请求会导致死锁,则不允许此次分配
(1)进程启动拒绝
(2)资源拒绝分配(银行家算法)
资源拒绝分配策略又称为银行家算法,该策略能够保证系统中进程和资源总是处于安全状态。当进程请求一组资源时,假设同意该请求,从而改变了系统的状态,然后确定其结果是否还处于安全状态,如果是,则同意这个请求;否则阻塞该进程直到同意该请求后系统状态仍然是安全的。
安全状态:
安全状态、不安全状态和死锁的关系:
银行家算法的前提:
银行家算法需要维护的信息:
其中,Max、Allocation以及Need的关系如下:
银行家算法中,需要判断系统是否处于安全状态,接下来介绍如何判断系统是否能够处于安全状态:
举例:
系统当前状态如下,判断其是否处于安全状态
现在P1、P2、P3、P4对应的Finish状态均为false,都是未完成状态
执行步骤2,找出状态为false,且所需资源(Need)小于等于系统当前剩余空闲资源(Available)的进程,发现P2符合条件,那么执行步骤3,分配资源给P2,P2执行完毕后,会将其资源释放,那么P2对应的Allocation和Need值将变为0 0 0,P2对应的Finish值也会变为true,然后系统当前剩余空闲资源(Available)的值将会增加变为6 2 3,如下图所示:
然后,再次执行步骤2,选择状态为false,且所需资源(Need)小于等于系统当前剩余空闲资源(Available)的进程,三个进程都符合条件,假设选择P1,则执行步骤3,各矩阵值变化如下:
再次执行步骤2(假设选择P3)和步骤3,矩阵值如下:
最后,再次执行步骤2和步骤3,P4执行完毕。所有进程都执行完毕,相应的Finish状态全部变为true,说明处于安全状态。
银行家算法的工作流程
知道如何判断系统是否处于安全状态后,接下来介绍银行家算法的工作流程:
举例:
初始状态如下,此时系统是处于安全状态的(安全序列:P2,P3,P1,P4,还有其他安全序列,不再举例)
此时,P1向系统发出请求,需要一个R1资源和一个R3资源,即1 0 1,那么采用银行家算法,是否会接受这个请求,向P1分配资源?
首先,假设接收P1的请求,向其分配资源:1 0 1,判断分配后的系统环境是否仍然为安全,如果安全则同意分配,否则不同意。
下图为分配后的系统环境:
判断是否有进程未执行完毕且其Need小于等于Available(系统当前空闲资源),发现并没有,所以系统处于不安全状态,因此,不会同意P1的请求。
从上面分析看出,银行家算法允许死锁必要条件中的互斥条件,占有并等待,不可抢占条件的存在,这样,它与死锁预防的几种方法相比较,限制条件少了,资源利用程度提高了。
这是该算法的优点。其缺点是:
- 这个算法要求客户数保持固定不变,这在多道程序系统中是难以做到的。
- 这个算法保证所有客户在有限的时间内得到满足,但实时客户要求快速响应,所以要考虑这个因素。
- 需要知道进程最大需要的资源是多少,一般是很难获得的。
- 由于要寻找一个安全序列,实际上增加了系统的开销。
3、死锁检测和死锁恢复
一般来说,由于操作系统有并发,共享以及随机性等特点,通过预防和避免的手段达到排除死锁的目的是很困难的。这需要较大的系统开销,而且不能充分利用资源。为此,一种简便的方法是系统为进程分配资源时,不采取任何限制性措施,但是提供了检测和解脱死锁的手段:定期进行死锁检测,发现死锁后对其进行恢复。
死锁检测
死锁检测方法:
(1)等待图:通过判断图中是否有环来判断是否死锁
(2)第二种方法和银行家算法中判断是否处于安全状态十分相似
死锁检测算法如下,和前面十分相似,就不再赘述:
和银行家算法类似,死锁检测过程开销很大。
死锁恢复
参考:
视频:操作系统-清华大学(向勇、陈渝)
《操作系统-精髓与设计原理》