银行家算法
在了解银行家算法之前,我们先回顾一下死锁产生的条件和处理方法
死锁产生的四个必要条件
1、互斥条件:一个资源每次只能被一个线程使用
2、请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
3、不剥夺条件:进程已获得的资源,在未使用之前,不能强行剥夺
4、循环等待条件:若干进程之间形成一种头尾相连接的循环等待资源关系
死锁的解除与预防
解决死锁的三种途径:预防、避免、检测与恢复。那么如何避免死锁,就是今天所要踢到的经典避免死锁方法——银行家算法。
避免死锁(银行家算法)
避免死锁的策略中,允许进程进行资源的动态的申请,系统在资源分配先进行预分配,先计算资源分配的安全性,不会导致系统进不到不安全的状态,系统会将资源真正的分配给进行。
银行家算法
当一个进程申请使用资源的时候,银行家算法通过先 试探 分配给该进程资源,
然后通过安全性算法判断分配后的系统是否处于安全状态,若不安全则试探分配作废,让该进程继续等待。
首先银行家算法的进程:
包含进程pi的需求资源的数量M(每个进程最大的需求你资源数量,MAX)
已分配的进程的资源A(Allocation)
还需要的资源数量N(Need=M-A)
系统资源池中空闲的资源数量:Avaliable(Available+已分配的资源数量A=系统中资源的总量)
通过安全性分析:找到了安全性序列:P0\p3\p4\p1\p2,当前的资源分配时安全的,即可以给线程进程资源分析,真正开始资源分配。
那么安全性分析的过程是什么呢?
安全性分析主要是通过安全性算法实现的!
安全性算法流程图:
(1) 设置两个工作向量Work=AVAILABLE;FINISH
(2) 从进程集合中找到一个满足下述条件的进 程,
FINISH==false;
NEED<=Work;
如找到,执行(3) ; 否则,执行(4)
(3) 设进程获得资源,可顺利执行,直至完 成,从而释放资源。
Work+=ALLOCATION;
Finish=true;
GOTO 2
(4) 如所有的进程Finish= true ,则表 示安全;否则系统不安全。
操作系统安全状态和不安全状态:
安全序列是指一个进程序列{P1,…,Pn}是安全的,如果对于每一个进程Pi(1≤i≤n),它以后尚需要的资源量不超过系统当前剩余资源量与所有进程Pj (j < i )当前占有资源
量之和。
如果存在一个由系统中所有进程构成的安全序列P1,…,Pn,则系统处于安全状态。安全状态一定是没有死锁发生。
不存在一个安全序列。不安全状态不一定导致死锁。
银行家算法代码实现
/**
* 银行家算法实现
*/
public class Banker {
int available[] = new int[]{3, 3, 2};//可得到的资源
int max[][] = new int[][]{{7, 5, 3}, {3, 2, 2}, {9, 0, 2}, {2, 2, 2}, {4, 3, 3}};//每个进程最大资源数
int allocation[][] = new int[][]{{0, 1, 0}, {2, 0, 0}, {3, 0, 2}, {2, 1, 1}, {0, 0, 2}};//每个进程目前拥有的资源数
int need[][] = new int[][]{{7, 4, 3}, {1, 2, 2}, {6, 0, 0}, {0, 1, 1}, {4, 3, 1}};//每个进程需要的资源数
void showData() {
//展示数据输出每个进程的相关数
System.out.println("进程号 Max All Need ");
System.out.println(" A B C A B C A B C");
for (int i = 0; i < 5; i++) {
System.out.print(i + " ");
for (int m = 0; m < 3; m++) System.out.print(max[i][m] + " ");
for (int m = 0; m < 3; m++) System.out.print(allocation[i][m] + " ");
for (int m = 0; m < 3; m++) System.out.print(need[i][m] + " ");
System.out.println();
}
}
boolean change(int inRequestNum, int inRequest[]) {
//分配数据
int requestNum = inRequestNum;
int request[] = inRequest;
if (!(request[0] <= need[requestNum][0] && request[1] <= need[requestNum][1] && request[2] <= need[requestNum][2])) {
//每一类请求资源小于当前线程need的资源数
System.out.println("请求的资源数超过了所需要的最大值,分配错误");
return false;
}
if ((request[0] <= available[0] && request[1] <= available[1] && request[2] <= available[2]) == false) {
//当前线程的每一类请求资源小于等于资源池对应资源的数量
System.out.println("尚无足够资源分配,必须等待");
return false;
}
for (int i = 0; i < 3; i++) {
//试分配数据给请求的线程
available[i] = available[i] - request[i];
//资源池的每类资源减去每类请求资源数量
allocation[requestNum][i] = allocation[requestNum][i] + request[i];
//当前线程allocation中每类资源加上每类资源请求数量
need[requestNum][i] = need[requestNum][i] - request[i];
//当前线程need中每类资源数量减去每类资源的请求数量
}
boolean flag = checkSafe(available[0], available[1], available[2]);//进行安全性检查并返回是否安全
if (flag == true) {
System.out.println("能够安全分配");
return true;
} else {
//不能通过安全性检查 恢复到未分配前的数据
System.out.println("不能够安全分配");
for (int i = 0; i < 3; i++) {
available[i] = available[i] + request[i];
allocation[requestNum][i] = allocation[requestNum][i] - request[i];
need[requestNum][i] = need[requestNum][i] + request[i];
}
return false;
}
}
boolean checkSafe(int a, int b, int c)//安全性检查
{
int work[] = new int[3];
work[0] = a;
work[1] = b;
work[2] = c;
int i = 0;
boolean finish[] = new boolean[5];
//寻找一个能够满足的认为完成后才去执行下一进程
while (i < 5) {
if (finish[i] == false && need[i][0] <= work[0] && need[i][1] <= work[1] && need[i][2] <= work[2]) {//找到满足的修改work值,然后i=0,重新从开始的为分配的中寻找
System.out.println("分配成功的是" + i);
for (int m = 0; m < 3; m++)
work[m] = work[m] + allocation[i][m];
finish[i] = true;
i = 0;
} else//如果没有找到直接i++
i++;
}
for (i = 0; i < 5; i++) {
//通过finish数组判断是否都可以分配
if (finish[i] == false)
return false;
}
return true;
}
public static void main(String[] args) {
Banker bank = new Banker();
bank.showData();
//请求线程资源存放的数组
int request[] = new int[3];
int requestNum;
String source[] = new String[]{"A", "B", "C"};
Scanner s = new Scanner(System.in);
String choice = new String();
while (true) {
//循环进行分配
System.out.println("请输入要请求的进程号(0--4):");
requestNum = s.nextInt();
System.out.print("请输入请求的资源数目");
for (int i = 0; i < 3; i++) {
System.out.println(source[i] + "资源的数目:");
request[i] = s.nextInt();
}
bank.change(requestNum, request);
System.out.println("是否再请求分配(y/n)");
choice = s.next();
if (choice.equals("n"))
break;
}
}
}