操作系统原理:死锁的特征,预防,避免,恢复

目录

一、死锁的资源占用图

二、死锁出现的特点

三、死锁预防

四、死锁避免

五、死锁检测和恢复


一、死锁的资源占用图

循环依赖导致资源无法释放而每个线程任务都无法执行完成。其中R表示资源集合,P表示进程/线程 ,每个点表示资源数,箭头表示请求和占用。

图 1)P1 依赖于 R1,而R1的剩余资源需要P2释放....用图来表示

     P1->R1;R1->P2; P2->R3;P3->R2;R2->{P1,P2}; 这就有一个循环依赖的环; 

    P1->P2,P2->P3  即 P1->P3 。由于P3依赖于P1和P2的其中1个释放资源P3->{P1,P2},且P1和P2都依赖于P3 同时 {P1,P2}->P3造成了死锁。

图2)并不是说资源占用图种有给“环”,就会发生死锁。

P1依赖于 P2,P3的其中一个释放资源 P1->{P2,P3} ,

P3->R2,  R2->{P1,P4} ,即 P3->{P1,P4} 其中P2没有依赖,P4没有依赖,虽然图中P1,P3存在一个“环”,但是这个环并不是进程间的依赖环,资源有机会被释放。所以不会构成死锁。

二、死锁出现的特点

死锁必然出现的现象

1)互斥:在同一时间内只能有一个进程使用资源

2)持有并等待: 进程持有至少1个资源正在等待其他进程的持有资源释放。

3)无抢占: 资源只能被进程执行完后自愿释放,不可获取其他进程正在占有的资源。

4)循环等待:进程间相互等待对方的资源先释放

三、死锁预防

只要接触上述发生死锁的4个必要条件中的一个就不会发生死锁。在实际操作系统的中,通常不进行死锁的预防,因为频繁检测会造成系统的开销很大。所以操作系统通常忽略死锁发生的问题。

1)限制申请方式:要么hold住所有的自己所需的资源,要么自己就不拿资源。这样做容易造成资源利用率低。

2)抢占: 当自己需要啥资源,叫其他进程释放掉资源。这种方法太暴力,不适合

3)解除循环等待:合理地打破循环依赖

四、死锁避免

    需要系统具有一定额外的先验信息的提供。死锁避免的方法开销要比死锁预防的开销要来得小。避免方法有很多种,通常的方法是找到一个进程安全序列,在序列前的进程先执行完才可以开始执行后面的进程。

1)要求进程声明需要的某类资源可能的最大数目,通过限定提供和分配的资源数量和进程的最大需求,用动态检查资源的分配状态,确保永远也不会有环形等待的出现。

2)按照安全序列顺序执行完任务。所谓安全序列的判定,每个Pj,Pi ,j<i 满足 Pi的资源需求不是立即可用的,那么需等到Pj完成在执行。就像图1,P1请求完R2执行,再去请求R1,说明R1不是P1立即可用的资源,所以P1需要等P2执行完后再执行。

银行家算法:再多个实例中找出一个安全序列并最大限度得利用资源

算法大致流程检查资源的剩余空闲量,检查进程的最大资源需求量和已分配资源量,并计算得到未来需求量:抽象的数据结构如下图: 其中need = request - allocation;所有成员由构造函数初始化得到。


class bankerAlgorithm{
 private:
 int n ; //进程数量
 int m ; //资源类型数量
 Matrix<int> request;  //进程所需的最大资源需求量矩阵request[i][j]=k表示Pi进程的所需类型Rj的资源数为k
 vector<int> available; //剩余资源空闲量向量,available[j]=k表示类型Rj的剩余资源数为k
 Matrix<int> allocation; //进程已分配的的资源数矩阵allocation[i][j]=k表示Pi进程的已分配类型Rj的资源数为k
 Matrix<int> need;    // 进程还需的资源数矩阵.need[i][j]=k表示Pi进程的还需类型Rj的资源数为k
 public :
 bankerAlgorithm (vector<Process> process, vector<Resource> res); //传进进程集合和矩阵集合
 void cal();
}

在示例中由 Pi,1<=i<=4   , 和Rj ,  1<=j<=4的请求的最大资源数Max,已分配的资源数allocation和还需分配的资源数 Need ,总资源数 R, 和还剩资源数 V 。在下图时刻,如何找到一个安全的执行序列呢?

1.首先找到比剩余资源V 还要小的进程还需资源数Need,从图中可以发现,比剩余资源数(0,1,1)还要小的资源数只有P2 (0,0,1)

2.等待P2进程执行完释放占有的资源(6,1,2) 后剩余资源到达 (6,2,3)

3.找到所需资源比剩余资源(6,2,3)少的进程,发现P1(2,2,2) 满足,在P1使用资源时,剩余资源可能会剩余到(4,0,1),发现没有资源可以满足其他进程。

4.等待P1进程执行完,释放所占用资源(1,0,0) 后剩余资源到达 (7,2,3)

5.找到所需资源比剩余资源(7,2,3)少的进程,发现P3(1,0,3) 满足,在P3使用资源时,剩余资源可能会剩余到(6.2.0),此时还可以满足P4进程的所需资源

最后得到的安全序列是  P1->P2->{P3,P4}

五、死锁检测和恢复

    死锁检测通常允许系统发生死锁,只不过隔段时间检测一次是不是发生了死锁,如果死锁存在就利用恢复机制。

    将资源请求/分配图,简化程进程间等待图。通过等待图判定进程间的依赖是否存在环。

死锁检测算法也是通过已占用资源判定 和 还需请求的资源判定,剩余资源能不能满足请求的资源。

例如总资源数(7,2,6),已分配资源数allocation 和 还需请求资源数Request , 剩余资源数 =  总资源数 -  已分配资源数。 

1.此时是 剩余资源数 (0,0,0) ,可以满足P0,待P0执行完后剩余资源数 (0,1,0)

2.此时是 剩余资源数 (0,1,0) ,可以满足P2,待P2执行完后剩余资源数 (3,1,3)

3.此时是 剩余资源数 (3,1,3) ,可以满足P1,待P1执行完后剩余资源数 (5,1,3)

4.此时是 剩余资源数 (5,1,3) ,可以满足P3,待P3执行完后剩余资源数 (7,2,4)

4.此时是 剩余资源数 (7,2,4) ,可以满足P4,待P3执行完后剩余资源数 (7,2,6)

只要发现由一条安全序列,那就不会发生死锁。如果真得检测出死锁,通常情况就是reboot 终止进程,直到死锁消除,例如操作系统的蓝屏,可以从进程的优先级,剩余运行时间等因素来选择进程终止。第二种方法是资源抢占,把资源的使用权让给另外一个进程。第三种方法是重启进程到安全状态等。

猜你喜欢

转载自blog.csdn.net/superSmart_Dong/article/details/117002209