来源:操作系统死锁的检测部分,学到一个死锁检测算法,模型基于邻接矩阵,检测有向图是否存在环路。
前提描述:n个进程,用邻接矩阵描述他们之间的依赖关系,如果R1需要R2先释放资源,那么在矩阵中记为1。对于一个3个进程的情况,如下图所示:
R0、R1、R2之间相互等待于是构成了死锁,在图中的效应就是构成了环路,我们要通过矩阵的运算,证明某个矩阵是否存在环路。
算法模型:for k:=1 to n do:
for i:=1 to n do:
for j:=1 to n do:
b[i][j]:=b[i][j]V(b[i][k]Λb[k][j]); //V相当于“或”运算,Λ相当于“与”运算。
我的理解、分析:i、j是对矩阵两个坐标的描述,k是什么呢?我理解的是”桥“,Ri通过Rk能到达Rj,则标记b[i][j]为1。我将从公式和程序验证的角度进行说明:
程序的验证,选用C语言进行模拟(ps:我的循环起点是零,但不影响结果,以下的分析都是以0为起点)
1 #include <stdio.h> 2 #define mapsize 3 3 int b[mapsize][mapsize] = { {0,1,0},{0,0,1},{1,0,0} }; 4 void mapout() { 5 int i, j; 6 for (i = 0; i < mapsize; i++) { 7 for (j = 0; j < mapsize; j++) { 8 printf("%d ", b[i][j]); 9 } 10 printf("\n"); 11 } 12 } 13 int main() { 14 int k, i, j, n; 15 n = mapsize; 16 for (k = 0; k < n; k++) { 17 for (i = 0; i < n; i++) { 18 for (j = 0; j < n; j++) { 19 20 printf("b[%d][%d]=b[%d][%d]||(b[%d][%d]&&b[%d][%d])=", i, j, i, j, i, k, k, j); 21 b[i][j] = b[i][j] || (b[i][k] && b[k][j]); 22 printf("%d\n",b[i][j]); 23 24 } 25 } 26 printf("--------------------------------\n"); 27 mapout(); 28 } 29 return 0; 30 }
当k=0时,矩阵运算后的结果如下图,“桥”,R2通过R0到达R1,标记b[2][1]=1。
当k=1时,矩阵运算后结果如下图,“桥”,R0通过R1能到达R2,标记b[0][2]=1;R2通过R0、R1能到达R2,标记b[2][2]=1。(列举到这里,相信你已经有所体会,所以我偷懒少写点)
运算的最终结果b[i][j]代表Ri能到达Rj,根据回路的定义“V0=Vk的通路”(V0起点,Vk终点),所以死锁存在判断的依据是,结果矩阵中是否存在b[i][i]=1(在死锁判断中,b[i][j]=b[j][i]也具有说服力,可以说明死锁特征的相互等待情况)。
公式验证,简单说一下,R0到R2,要么R0直连R2,要么R0->R1->R2,用数学语言描述为:b[0][2]=1或者(b[0][1]=1且b[1][2]=1),结合0、1运算特性,公式:b[i][j] = b[i][j] || (b[i][k] && b[k][j]);
k在这里就是1,是个“桥”。(如果老师问你,你回答k是“桥”,然后GG了,本人不负责任)
环路检测的话,多是使用的深度遍历、广度遍历的搜索方法。两种方法的时间复杂度是O(n^2),显然优于三层循环方法。 (写到这里,似乎上学期算法课,当时的老师没讲清楚,我分析过一波K!!!删博警告)