银行家算法
一种避免死锁的算法,由Dijkstra发明。
假定系统中有n个进程,m类资源,银行家算法使用的数据结构如下
1. 可利用资源向量Available[m]
Available[i]表示第i类资源的现有空闲数量。
2. 最大需求矩阵Max[n][m]
Max[i][j]表示第i个进程对第j类资源的最大需求。
3. 分配矩阵Allocation[n][m]
Allocation[i][j]表示第i个进程当前拥有第j类资源的数量。
4. 需求矩阵Need[n][m]
Need[i][j]表示第i个进程还需要第j类资源的数量。
Allocation + Need = Max
算法Java实现
下面这段代码是银行家算法的实现
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Banker {
private int resN;
private int processN;
private int[] available;
private final int[][] MAX;
private int[][] need;
private int[][] allocation;
private int[] work;
private boolean[] finish;
public Banker(int[] availableRes, int[][] max) {
available = availableRes;
resN = available.length;
processN = max.length;
MAX = max;
need = new int[processN][resN];
for (int i = 0; i < processN; i++) {
for (int j = 0; j < resN; j++) {
need[i][j] = MAX[i][j];
}
}
allocation = new int[processN][resN]; // allocation + need = MAX;
work = new int[resN];
finish = new boolean[processN];
}
public boolean request(int process, int[] requestRes) {
if (!validate(process, requestRes))
return false;
boolean result = bank(process, requestRes);
printRequest(process, requestRes);
printState();
return result;
}
private boolean bank(int process, int[] requestRes) {
// 1. 预分配
for (int i = 0; i < resN; i++) {
available[i] -= requestRes[i];
allocation[process][i] += requestRes[i];
need[process][i] -= requestRes[i];
}
// 2. 检查是否进入安全状态
if (isSecureState())
return true;
// 3. 分配后进入非安全状态,取消分配
for (int i = 0; i < resN; i++) {
available[i] += requestRes[i];
allocation[process][i] -= requestRes[i];
need[process][i] += requestRes[i];
}
return false;
}
private boolean isSecureState() {
int[] secure = new int[processN];
for (int i = 0; i < resN; i++) {
work[i] = available[i];
}
for (int i = 0; i < processN; i++) {
finish[i] = false;
}
for (int i = 0; i < processN; i++) {
// Find a process which need < work.
for (int j = 0; j < processN; j++) {
if ((!finish[j]) && isAvailableEnough(j)) {
for (int k = 0; k < resN; k++) {
work[k] += allocation[j][k];
}
secure[i] = j;
finish[j] = true;
break;
}
// The available is not enough for all processes.
if (j == processN - 1) {
System.out
.println("Request fail. It will go to the unsecure state.");
return false;
}
}
}
System.out.print("The secure array : ");
for (int i = 0; i < processN; i++) {
System.out.print(secure[i] + " ");
}
System.out.println();
return true;
}
private boolean isAvailableEnough(int process) {
for (int i = 0; i < resN; i++) {
if (work[i] < need[process][i])
return false;
}
return true;
}
private boolean validate(int process, int[] requestRes) {
for (int i = 0; i < resN; i++) {
if (requestRes[i] > available[i]) {
printRequest(process, requestRes);
System.out.println("Request fail. Request for resource " + i
+ " is larger than available.");
printState();
return false;
} else if (requestRes[i] > need[process][i]) {
printRequest(process, requestRes);
System.out.println("Request fail. Request for resource " + i
+ " is larger than process " + process + " needs.");
System.out.println();
printState();
return false;
}
}
return true;
}
public void printState() {
System.out.print("Available = ");
for (int i = 0; i < resN; i++) {
System.out.print(available[i] + " ");
}
System.out.println();
System.out.println("MAX Allocation Need");
for (int i = 0; i < processN; i++) {
for (int j = 0; j < resN; j++) {
System.out.print(MAX[i][j] + " ");
}
System.out.print(" ");
for (int j = 0; j < resN; j++) {
System.out.print(allocation[i][j] + " ");
}
System.out.print(" ");
for (int j = 0; j < resN; j++) {
System.out.print(need[i][j] + " ");
}
System.out.println();
}
System.out.println();
}
private void printRequest(int process, int[] requestRes) {
System.out.print("Request " + process + " = ");
for (int i = 0; i < resN; i++) {
System.out.print(requestRes[i] + " ");
}
System.out.println();
}
public static void main(String[] args) throws IOException {
int[] available = { 10, 8, 7 };
final int[][] MAX = { { 7, 5, 3 }, { 3, 2, 2 }, { 9, 0, 2 }, { 2, 2, 2 }, { 4, 3, 3 } };
Banker banker = new Banker(available, MAX);
BufferedReader is = new BufferedReader(new InputStreamReader(System.in));
banker.printState();
while (true) {
try {
System.out.print("Please input the request: ");
String input = is.readLine();
if ("q".equals(input))
break;
String[] data = input.split(" ");
int process = Integer.valueOf(data[0]);
int[] requestRes = new int[available.length];
for (int i = 0; i < available.length; i++) {
requestRes[i] = Integer.valueOf(data[i + 1]);
}
banker.request(process, requestRes);
} catch (Exception e) {
System.out.print("Error");
}
}
is.close();
}
}
现在来解释银行家算法的过程。
1. 进程i向系统提出资源请求。
public boolean request(int process, int[] requestRes) {
if (!validate(process, requestRes))
return false;
boolean result = bank(process, requestRes);
printRequest(process, requestRes);
printState();
return result;
}
requestRes表示对各类资源的申请数量。
2. request方法首先调用validate方法对资源请求进行审核。
private boolean validate(int process, int[] requestRes) {
for (int i = 0; i < resN; i++) {
if (requestRes[i] > available[i]) { // 审核标准1
printRequest(process, requestRes);
System.out.println("Request fail. Request for resource " + i
+ " is larger than available.");
printState();
return false;
} else if (requestRes[i] > need[process][i]) { // 审核标准2
printRequest(process, requestRes);
System.out.println("Request fail. Request for resource " + i
+ " is larger than process " + process + " needs.");
printState();
return false;
}
}
return true;
}
审核标准1,Request <= Available,若不满足,则表示可用资源不够。
审核标准2,Request <= Need,若不满足,则表示请求的资源数超出了需要的资源数。
3. 满足上述审核标准后,对进程i请求的资源进行预分配。
private boolean bank(int process, int[] requestRes) {
// 1. 预分配
for (int i = 0; i < resN; i++) {
available[i] -= requestRes[i];
allocation[process][i] += requestRes[i];
need[process][i] -= requestRes[i];
}
// 2. 检查是否进入安全状态
if (isSecureState())
return true;
// 3. 分配后进入非安全状态,取消分配
for (int i = 0; i < resN; i++) {
available[i] += requestRes[i];
allocation[process][i] -= requestRes[i];
need[process][i] += requestRes[i];
}
return false;
}
4. 对修改后的状态向量进行安全性算法检测,若分配后进入非安全状态,则取消分配,如上述代码第3步。
5. 安全性检测算法
查找是否存在安全序列。若在某一时刻,系统能按某种顺序为每个进程分配其所需的资源,直到最大需求,使每个进程都可顺利完成,则称此时的系统状态为安全状态,该序列为安全序列。
private boolean isSecureState() {
int[] secure = new int[processN];
for (int i = 0; i < resN; i++) {
work[i] = available[i];
}
for (int i = 0; i < processN; i++) {
finish[i] = false;
}
for (int i = 0; i < processN; i++) {
// 查找满足2个条件的进程:1.Finish[i]=false; 2.Need<=Work
for (int j = 0; j < processN; j++) {
if ((!finish[j]) && isAvailableEnough(j)) {
for (int k = 0; k < resN; k++) {
work[k] += allocation[j][k];
}
secure[i] = j;
finish[j] = true;
break;
}
// The available is not enough for all processes.
if (j == processN - 1) {
System.out
.println("Request fail. It will go to the unsecure state.");
return false;
}
}
}
...
return true;
}
private boolean isAvailableEnough(int process) {
for (int i = 0; i < resN; i++) {
if (work[i] < need[process][i])
return false;
}
return true;
}
1.首先创建了长度为m的向量Work[m],长度为n的向量Finish[n],初始化Work=Available,Finish[n]=false;
2.查找满足如下2个条件的进程:1. Finish[i]=false; 2. Need<=Work。若没有这样的进程存在,则表示进程进入非安全状态。
3.如果找到满足条件进程i,则将Finish[i]设为true,表示当前可使用的资源数量可以让进程i正常结束,同时Work=Work+Allocation[i],表示进程i结束后,可使用的资源数。然后返回2继续查找。
4.如果所有进程,Finish都为true,那么表示有一个进程运行序列可以保证不会发生死锁,此时系统处于安全状态。反之,则系统处于不安全状态,并取消分配。
代码运行结果
读者可以自己运行测试。
Available = 10 8 7
MAX Allocation Need
7 5 3 0 0 0 7 5 3
3 2 2 0 0 0 3 2 2
9 0 2 0 0 0 9 0 2
2 2 2 0 0 0 2 2 2
4 3 3 0 0 0 4 3 3
Please input the request: 0 0 1 0
The secure array : 0 1 2 3 4
Request 0 = 0 1 0
Available = 10 7 7
MAX Allocation Need
7 5 3 0 1 0 7 4 3
3 2 2 0 0 0 3 2 2
9 0 2 0 0 0 9 0 2
2 2 2 0 0 0 2 2 2
4 3 3 0 0 0 4 3 3
Please input the request: 1 2 0 0
The secure array : 0 1 2 3 4
Request 1 = 2 0 0
Available = 8 7 7
MAX Allocation Need
7 5 3 0 1 0 7 4 3
3 2 2 2 0 0 1 2 2
9 0 2 0 0 0 9 0 2
2 2 2 0 0 0 2 2 2
4 3 3 0 0 0 4 3 3
Please input the request: 2 3 0 2
The secure array : 1 0 2 3 4
Request 2 = 3 0 2
Available = 5 7 5
MAX Allocation Need
7 5 3 0 1 0 7 4 3
3 2 2 2 0 0 1 2 2
9 0 2 3 0 2 6 0 0
2 2 2 0 0 0 2 2 2
4 3 3 0 0 0 4 3 3
Please input the request: 3 2 1 1
The secure array : 1 3 0 2 4
Request 3 = 2 1 1
Available = 3 6 4
MAX Allocation Need
7 5 3 0 1 0 7 4 3
3 2 2 2 0 0 1 2 2
9 0 2 3 0 2 6 0 0
2 2 2 2 1 1 0 1 1
4 3 3 0 0 0 4 3 3
Please input the request: 4 0 0 2
The secure array : 1 3 0 2 4
Request 4 = 0 0 2
Available = 3 6 2
MAX Allocation Need
7 5 3 0 1 0 7 4 3
3 2 2 2 0 0 1 2 2
9 0 2 3 0 2 6 0 0
2 2 2 2 1 1 0 1 1
4 3 3 0 0 2 4 3 1
Please input the request: 1 1 0 2
The secure array : 1 3 0 2 4
Request 1 = 1 0 2
Available = 2 6 0
MAX Allocation Need
7 5 3 0 1 0 7 4 3
3 2 2 3 0 2 0 2 0
9 0 2 3 0 2 6 0 0
2 2 2 2 1 1 0 1 1
4 3 3 0 0 2 4 3 1
Please input the request: 0 2 4 0
The secure array : 1 3 0 2 4
Request 0 = 2 4 0
Available = 0 2 0
MAX Allocation Need
7 5 3 2 5 0 5 0 3
3 2 2 3 0 2 0 2 0
9 0 2 3 0 2 6 0 0
2 2 2 2 1 1 0 1 1
4 3 3 0 0 2 4 3 1
Please input the request: 3 0 1 0
Request fail. It will go to the unsecure state.
Request 3 = 0 1 0
Available = 0 2 0
MAX Allocation Need
7 5 3 2 5 0 5 0 3
3 2 2 3 0 2 0 2 0
9 0 2 3 0 2 6 0 0
2 2 2 2 1 1 0 1 1
4 3 3 0 0 2 4 3 1
Please input the request:
算法意义
银行家算法虽然很有意义,但是缺乏实用价值。原因如下:
1. 因为很少有进程在运行前就知道它所需资源的最大值
2. 进程数在不断变化(新用户的登录或退出)
3. 原本可用的资源也可能突然间变得不可用(如磁带机可能会坏掉)