本文讲解操作系统的死锁,主要分为以下几个部分:
- 资源分配图
- 死锁特征
- 死锁处理
- 死锁预防
- 死锁避免
- 死锁检测
- 死锁恢复
- 银行家算法实现
资源分配图
资源分配图就是用圆圈和方块分别表示进程和资源,资源中的小圆点的个数表示资源数目,如下图
其中从一个进程指向一个资源的边称为等待边,也叫申请边,就是申请一个资源; 而从一个资源指向进程的边称为占有边,也叫分配边,表示这个资源分配给了某个进程,如图中: 分别是等待边和占有边。
可以发现有环是发生死锁的必要条件,i.e. 发生死锁一定存在一个环,但存在环并不一定发生死锁,如右图
死锁特征
也叫死锁的必要条件:
- 互斥: 至少一个资源处于非共享状态
- 占有并等待: 存在一个进程占有至少一个非共享资源同时等待另外一个被其他进程占有的资源
- 非抢占: 即资源不能被抢占,即资源只能在进程完成任务后自动释放
- 循环等待: 即有一组循环等待进程 , 等待 的资源, 等待 的资源…(即出现环)
因此要避免死锁只需要破坏一个必要条件就好。
死锁处理
其实死锁检测的开销是很大的,而死锁在 PC机中又很少发生,所以其实在真实的操作系统中,比如: Windows,Linux 其实都是直接忽略死锁的,一般重启就好了。这里简要的介绍一些方法,重点掌握银行家算法即可
死锁预防
就是可以针对这4个必要条件,逐一采取相应措施就好,需要注意的是,这种限制资源申请的方法,其实会降低设备使用率和系统吞吐率
死锁避免
安全状态:
如果存在一个进程作业序列: , 需要申请的资源小于等于当前可用资源加上 的资源。 那么这个序列就是安全的。
我们这里主要讲解银行家算法, 判断是否安全。
银行家算法
首先我们定义如下变量:
- avl[m]: 每种资源的现有实例
- maxRes[n][m]: 每个进程所需的最大资源
- alloc[n][m]: 每个进程已经分配的资源
- need[n][m]: 每个进程还需要分配的资源(need[i][j] = max[i][j] - alloc[i][j])
所谓应行家算法就是,先将资源预先分配给这个进程,然后模拟一下,看看是否系统是安全的。
安全性检测算法
- work[m]: 可用资源
- finish[n]: 每个进程是否能结束
1) 初始化 work = avl,finish = false for i = 1 to n
2) find a proc i s.t Finish[i] = false and need[i] <= wok
3) work+=avl;finish[i] =true;
4) if not find the i s.t condition. 如果所有i finish[i]=true,那么安全,否则不安全
算法的时间复杂度为
细节请见文末代码
资源请求算法
这个很简单,就先检测能不能分配,如果能,就先分配给他,然后再用上面的安全性检测算法做个检测就好了。
应行家算法java实现
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import com.sun.istack.internal.FragmentContentHandler;
import com.sun.javafx.geom.Edge;
import com.sun.org.apache.bcel.internal.generic.ReturnaddressType;
/**
* @author zouzhitao
*
*/
public class Main {
public static Scanner in = new Scanner(new BufferedInputStream(System.in));
public static void main(String[] args) {
int[][] alloc = new int[][]{{0,1,0},{2,0,0},{3,0,2},{2,1,1},{0,0,2}};
int[][] max = new int[][]{{7,5,3},{3,2,2},{9,0,2},{2,2,2},{4,3,3}};
int[] avl = new int[]{3,2,2};
Banker banker = new Banker(avl, max, alloc);
System.out.println(banker.testSafe());
int[] rqs = new int[3];
int idx =0;
while (true) {
idx = in.nextInt();
for(int i=0 ; i<rqs.length; ++i)
rqs[i] = in.nextInt();
System.out.println(banker.request(idx, rqs));
}
}
}
/*
* 应行家算法
*/
class Banker{
private int[] avl; // 可用分配资源数目
private int[][] maxRes;//最大资源数目
private int[][] alloc;// 以分配资源数目
private int[][] need;//每个进程所需剩余资源
private int[] work;// 辅助数组
private boolean[] finish;
private int n,m;
public Banker(int[] avl, int[][] maxRes, int[][] alloc) {
super();
this.avl = avl;
this.maxRes = maxRes;
this.alloc = alloc;
n = maxRes.length;
m = avl.length;
work = new int[m];
finish = new boolean[n];
need = new int[n][m];
for(int i=0 ; i<n ; ++i)
for(int j=0 ; j<m ; ++j)
need[i][j] = maxRes[i][j] - alloc[i][j];
}
//safe test
public boolean testSafe() {
Arrays.fill(finish, false);
for(int i=0 ; i<m ; ++i)work[i] = avl[i];
boolean notFinish = true;
while (notFinish) {
notFinish = false;
// find a proc i ,s.t finish[i]=false && need[i]<=work;
for(int i=0 ; i<n ; ++i)
if(!finish[i]){
if(cmp(need[i], work)){
addArr(alloc[i], work);//work += alloc[i];
finish[i] = true;
notFinish = true;
}
}
}
for(int i=0 ; i<n ; ++i)
if(!finish[i])return false;
return true;
}
// request resource test
public boolean request(int prc_idx,int[] rqs) {
for(int i=0 ; i<m ; ++i)
if(rqs[i]>need[prc_idx][i]){
System.err.println("request resource bigger than need resource");
return false;
}
for(int i=0 ; i<m ; ++i)
if(rqs[i] > avl[i]){
System.out.println("no avilable resource! process must wait");
return false;
}
subArr(rqs, avl);
addArr(rqs, alloc[prc_idx]);
subArr(rqs, need[prc_idx]);
if(testSafe())return true;
else{
System.out.println("dead lock");
// recover resource
addArr(rqs, avl);
subArr(rqs, alloc[prc_idx]);
addArr(rqs, need[prc_idx]);
return false;
}
}
private boolean cmp(int[] a,int[] b) {
assert a.length==b.length :" the compare arrays have diff length";
for(int i=0 ; i<a.length ; ++i)
if(a[i]!=b[i])return a[i] <=b[i];
return true;
}
/*
* des[] -= a[];
*/
private static void subArr(int[] a,int[] des) {
assert a.length==des.length :" the compare arrays have diff length";
for(int i=0 ; i<a.length ; ++i)des[i]-=a[i];
}
/*
* des[]+=a[];
*/
private static void addArr(int[] a,int[] des) {
assert a.length==des.length :" the compare arrays have diff length";
for(int i=0 ; i<a.length ; ++i)des[i]+=a[i];
}
private static void printArr(int[] arr) {
for(int i=0; i<arr.length ; ++i)System.out.print(arr[i]+" ");
System.out.println();
}
public void print() {
System.out.println("max resource matrix");
for(int i=0 ; i<n ; ++i)printArr(maxRes[i]);
System.out.println("allocation matrix");
for(int i=0 ; i<n ; ++i)printArr(alloc[i]);
System.out.println("need matrix");
for(int i=0 ; i<n ; ++i)printArr(need[i]);
System.out.println("avliable vector");
printArr(avl);
}
}