如果不了解死锁,可以通过这篇文章进行了解:死锁的概念及资源分配图

我们都知道,操作系统可能会遇到死锁这种情况,那么处理死锁的方法有哪些呢?处理死锁和我们生活中遇到的消防很“类似”

下面就是4种应付死锁的方法:

  • 死锁预防(Deadlock Prevention):确保系统永远不会进入死锁状态。

举个例子,消防上为了预防火灾,如果禁止在任何时刻任何地点使用任何的火,这样就可以保证不会发生火灾了。

我们都知道,产生死锁需要同时满足4个条件,如果我们把这4个条件中的任何一个去掉,也可以避免进入死锁。但是如果不让进程使用这些资源,那也会带来新的问题,那就是系统对计算机软硬件的资源利用效率会变很低

  • 死锁避免(Deadlock Avoidance):在使用前进行判断,只允许不会出现死锁的进程请求资源。

从消防防火的角度来说,这就相当于允许用火,但会采用严格的监管措施去监管,在某时刻某空间到底是否允许用火,会有一个严格的审批流程,比如在某些区域里,不完全禁止用火,但只允许拥有某些资质的人使用,也就是只允许不会出现死锁的进程请求资源。

然鹅实际上,消防部门的精力是有限的,当操作系统管理不过来时,后面的那些进程申请资源,光审批流程就要等很久很久了。

  • 死锁检测和修复(Deadlock detection&recovery):在检测到运行系统进入死锁状态后,再进行修复。

类比于消防就是,因为申请用火的市民太多了(申请资源的进程太多了),政府部门已经管理不过来,那就放弃管理了(不预防死锁也不避免死锁),采用无为而治的方法,你想用火就随便用,只是一旦发现火情了,消防部门马上出动,进行灭火行动。也就是在检测到运行系统进入死锁状态后,再进行修复,解决死锁这个问题。

  • 撒手不管法:由应用进程自己处理死锁。

因为火情有大有小,很小很小的火情比如一块纸着火了,压根就不需要兴师动众地出动消防兵和消防车,那就让用火的市民自己去处理吧,既不预防,也不救火了。

实际上,大部分操作系统(包括Unix)确实是忽略死锁的,这些都交给应用进程自己去处理


下面详细介绍一下前面2种方法。

① 死锁预防:限制申请方式,预防是采用某种方式,限制并发进程对资源的请求,使系统在任何时刻都不满足死锁的必要条件。

只要把4个条件里的其中任何一个,想办法弄成不满足就行了。

  • 互斥:把互斥的共享资源封装成可同时访问

以前的打印机是不可以同时打东西,需要互斥地打印,如果两个进程同时给打印机发送打印作业,那么打印出来的东西,是谁都不需要的,因为已经乱了。但是现在的打印机,我们感受不到这一点,因为现在的打印机都加入了缓冲机制,两个进程可以同时给打印机发送打印作业,但是打印机会在内部自己协调,先打印哪个后打印哪个。这就是把互斥地把资源——打印机封装成可同时访问。

  • 持有并等待:进程请求资源时,要求它不持有任何其他的资源

因为请求资源时,不能持有任何其他的资源,所以需要在进程一开始执行时,就把所有需要的资源都请求下来。进行一个比喻,你需要做一笔工程项目,但是需要很多钱,于是到银行申请贷款,一次性把需要的所有的钱都申请贷款下来。但是这样有个问题,假如你需要修一个水电站,这需要很大笔的花费,而且要修10几年,这么多钱这么长时间,利息是很高的你的压力是非常大的。对应的对操作系统来说,那就是资源的利用效率太低

  • 非抢占:如进程请求不能立即分配的资源,则释放已占有的资源。(只在能够同时获得所有需要的资源时,才执行分配操作。)

这个例子的话,对应的就是我在上文的博客中提到的,在一个单向通行的桥梁中,如果两辆相向行驶的车撞上了,车A和车B请求的资源都不能立即分配,则需要释放已占有的资源,对应的就是车A和车B都往后撤退,然后下一个时刻,车A或车B中某一辆就可以通过了,一辆车通过单向桥后,另一辆也可以通过了。

  • 循环等待:对资源排序,要求进程按顺序来请求资源

这种方法依然会使效率下降不少,比如我先申请某一部分资源,但是却是很久后才使用。


② 死锁避免:利用额外的先验信息,在分配资源时判断是否会出现死锁,只有在不会死锁时才分配资源。

相当于你去银行借款,银行根据你的信用状况和经济能力,来判断借钱给你,你是否会如期归还,并不在乎你以前有没有借过钱或者是否还欠着钱。

对应在操作系统里的做法是,要求进程声明需要资源的最大数目,限定提供与分配的资源数量,确保满足进程的最大需求,然后再动态检查资源分配状态,确保不会出现环形等待(利用资源分配图进行判断)

当进程请求资源时,系统会判断分配后的资源是否处于安全状态。

那么什么样的状态是安全的呢?方法是,针对所有已占用资源的进程,P1到Pn,使用一个安全序列<P1,P2,P3,...,Pn>,这个安全序列是按照这个条件:Pi要求的资源≤当前可用资源+所有Pj持有资源,其中j<i  进行排序的。

如果Pi的资源请求不能立即分配,则Pi等待所有Pj(j<i)完成;Pj完成后,Pi也可以完成了,Pi完成后,Pi+1可得到所需的资源,执行并释放所分配的资源;最终组中整个序列的所有进程都能获得所需的资源....

那么这个安全状态与死锁是什么关系呢?

ShardingDataSource PreparedStatementExecutor execute 的死锁问题 死锁的解决_互斥

用韦恩图可以很好的表示:处于安全状态的一定不会发生死锁;但处于不安全状态的,不一定会发生死锁