前言

死锁问题是面试官最喜欢的问题,我在之前的一篇文章里写了死锁的产生条件,这里我写一个死锁的预防算法。

银行家算法

为什么叫银行家算法呢?其实就是类比银行给客户放贷这件事情。银行家手里的资金是有限的,他决定是否给某个顾客放贷,得看一看自己手上的剩余资源,和顾客的贷款额度。

大概说一下算法流程

首先呢,银行家算法会创建一些资源列表,包括初始化时最大资源数量列表,目前剩余的资源数量列表。
那么进程呢,也有自己的一套资源列表,分别是当前线程能请求的最大资源数量列表、目前已经请求到的资源数量列表、目前还想请求的资源数量列表。
OK一共系统+进程的资源列表就这五个。
现在咱们开始模拟银行家算法。
1.进程提出request资源请求,里面其实就是个自愿请求列表。然后银行家算法会比较request请求和五大列表之“用户还想请求的资源列表”。啥意思呢?这个用户进程明明需要的只是need列表,但是它居然请求了request列表且request>need!那对不起,出错!如果没出错的话,就下一步!
2.继续做检测,这次进程与系统的检测。一句话,你总不能请求的资源数量比当前剩余的资源数量还要多吧?不过也没关系,多的话就把你这个进程先阻塞起来。然后咱等着,一直等到你这个进程被唤醒了,且资源数够分配了,就尝试给你分配一下。
3.先虚假的给进程分配它想要的request(为什么说是虚假的呢,后面慢慢看),然后转手就去做安全检查。啥意思呢?就是说,虽然系统目前剩余资源确实够给你这个进程分配,但是这不是我的唯一的安全检查。
这里我先停下来给各位解释清楚。有的线程很恶心的,它手上已经拿了一些系统的资源了,可是呢,它还是会继续请求新的系统资源,对,它没吃饱。进程没那么聪明的,它虽然手上已经有一些系统资源了,可是在它申请新的资源时,如果没成功,它就会一直卡在申请新资源这个地方,卧槽,那之前的资源不就一直卡在这个傻子手上了么?对啊!这不就死锁了么?所以啊,为了照顾这些巨婴,得让他们有能力先把自己的新的资源申请成功了,这样它才有可能全部释放资源。
所以咱们还得做这样的一个安全检查:必须得保证,所有进程队列里的进程,有能力申请到自己的新的资源,然后我们假设它完全释放了自己的旧的和新的资源,扩充系统剩余资源后,继续对剩下的所有的进程执行这个判断,直到所有的进程都能满足申请新的资源,那就可以给刚刚那个进程真正的分配资源了。
4.如果安全检查没通过,那么抱歉,我不能分配给你资源,刚刚的虚假分配,撤销!你这个进程请阻塞掉。

引用一下博客园@王陵的一张图

银行家算法-避免死锁的好方法

具体实例

大家看一下这张图:
银行家算法-避免死锁的好方法
这是to时刻的系统与进程的资源分配情况。
现在呢,P1进程想分配资源,咱们能给他么?
显然不行啊,它的need超过了系统的available!
那么P1就阻塞了。
接下来是P2,咱们能给他分配么?显然,咱们剩余的资源还够用,于是就假装先给它,那么咱们剩余资源就成了0 1 0了。这就完了么?肯定没啊,咱们得做安全性检查。首先看看P2,假设P2申请完资源后会全部释放资源,于是咱们的剩余资源成了6 2 3。
继续看看P1,它现在有了申请新资源的能力了,因为咱们的剩余资源成了6 2 3了,那么咱们假设P1申请了资源以后就释放了自己所有的资源,于是剩余资源成了7 2 3了,继续!
咱们继续看看P3,肯定也没问题了,于是继续假设P3申请完资源后释放了全部资源,balabala
P4咱就不说了。
于是顺了一圈发现,嘿嘿嘿,都没问题。
于是P2才真正得到了资源。

总结

其实银行家算法针对的,是那些已经分配到了一些系统资源,但是还想申请更多的系统资源,结果导致申请失败但是系统让他阻塞了,这么一来它手上有的资源就死锁了。你想申请新的资源,可以,但是你得保证,其他人有机会申请到新的资源(这样它才能不会卡住,也就有能力释放掉自己的所有资源)。

相关文章: