第六章 死锁
0.死锁实例:
eg1:有A、B两个进程都想将文件扫描并刻录光盘,A先请求扫描仪,被允许;B先请求光盘刻录机,被允许;接下来它们同时去申请对方拥有的东西,都不被允许,于是互相等待,由此产生死锁。
eg2:数据库系统中,进程A给R1加锁,进程B给R2加锁,接着这两个个进程又试图给对方的记录加锁,这样也产生了死锁。
6.1 资源
通过上述例子我们发现,死锁的产生都源于两个(或多个)进程请求对方所拥有的对象,而这类对象具有排他性,我们就称这类对象为资源。
6.1.1 可抢占资源和不可抢占资源
可抢占资源可以从拥有它的进程中抢占而不会产生任何副作用(比如计算机内存)。相反地,不可抢占资源是指无法把资源从占有它的进程处抢占过来而不产生任何副作用。而死锁,就与这类不可抢占资源有关.
6.2 死锁简介
死锁的规范定义:如果一个进程集合中的每个进程都在等待只能由该进程集合中的其他进程才能引发的事件,那么该进程集合就是死锁的。
6.2.1 死锁产生的四个条件
1)互斥条件 资源要么只分配给一个进程,要么可用
2)占有和等待 已经得到某个资源的进程可以申请新资源
3)不可抢占 已经分配的资源不能抢占,只能释放
4)环路等待 死锁发生时,一定有环路
以上四个条件同时满足,就会产生死锁。
6.2.2 资源分配图
6.3 死锁的检测和恢复
允许死锁发生,在发生后采取措施进行恢复
6.3.1 死锁的检测方法
对于每种类型资源只有一个的死锁,我们可以画资源分配图来判断其中有没有环路,转化到计算机里就是一个如何检测有向图环路的问题。
对于每种类型资源都有多个的情况,就要通过矩阵检测:
设Ei(1<=i<=m)代表每一种资源总量,m为资源类型数。Ai为当前每种资源的可用资源数。构造当前分配矩阵(Cij),row代表进程,col代表资源,第n行就是第n个进程拥有的所有资源表。同理构造请求矩阵(Rij)。
具体算法如下:
1)寻找一个没有标记的进程Pi,对于它而言R矩阵的第i行向量小于或等于A(就是请求小于等于可用的意思)
2)找到这样一个进程后,想象已经将资源分配给了它,它已经运行完毕释放资源,所以就要将C矩阵的第i行向量加到A中,标记该进程并转到第一步
3)没有找到这样的进程则算法终止
在整个过程结束后,如果有没有标记过的进程,就产生了死锁。
6.3.2 恢复
1.利用抢占恢复
人工干预将某个资源转移给另外的进程。这种做法的可行性取决于资源本身的特性。
2.回滚恢复
周期性地对进程进行检查点检查:将进程的状态写入一个文件以备重启。该检查点中不仅包括存储映像,还包括了资源状态,即哪些资源分配给了该进程。而且检查点文件不会覆盖,而是连起来形成一系列文件。。一旦检测到死锁,明确了它需要哪些资源。这样拥有所需资源的进程就会回到拥有这个资源前的检查点。
3.通过杀死进程恢复
杀掉环中的进程或者选一个环外拥有环内所需资源的进程杀掉。最好杀掉可以从头开始运行而不会产生副作用的进程。
6.4 避免死锁
银行家算法:
明确四个要素:E:资源向量 A:当前可分配资源向量 矩阵C:进程分配矩阵 矩阵R:进程需求矩阵
先进行试分配,看最后是否能产生一个安全序列,如果没有产生,则不进行分配;产生,则序列安全,按序列顺序进行资源分配
6.5 预防死锁
6.5.1 破坏互斥条件
让资源不被进程独自占有。比如假脱机打印技术
6.5.2 破坏占有并等待条件
规定所有进程在开始执行前请求所需的全部资源,如果所需的全部资源可用,那么就进行分配和运行。
6.5.3 破坏不可抢占条件
通过虚拟化的方式来实现可抢占。假脱机打印机向磁盘输出,并且只允许打印机守护进程访问真正的物理打印机,这种方式可以消除设计打印机的死锁,然而却可能带来由磁盘空间导致的死锁。但是磁盘空间通常都比较大,比较少见空间用完的情况。
6.5.4 破坏环路等待条件
将资源统一编号,每个进程都只能按照编号的顺序获取资源。
该方案的一个变种是取消必须按升序请求资源的限制,而仅仅要求不允许进程请求比当前所占有资源编号低的资源。
6.6 其他问题
6.6.1 通信死锁
在通信系统中,进程A向进程B发送消息,然后进程A阻塞至B回复;假如请求丢失,就造成了A阻塞等回复,B阻塞等消息的局面。这就是通信死锁。
中断此类死锁的方法是:超时。发送方在发送消息后开启一个计时器,若计时器停止还没得到回复,则重传消息。
Tips:网络中也有可能产生资源死锁的问题,比如在路由器中传输数据包
6.6.2 活锁
进程A获得了资源1,进程B获得了资源2,然后它们请求对方的资源,发现请求不到,于是释放自己的资源一段时间,再次请求,问题是如果释放的时间一样,上述过程就会一直重复,这样进程看起来是在运行,但是并不会执行什么有用的任务,称为活锁。