一、實驗內容
銀行家算法的實現。
二、實驗目的
銀行家算法是一種最有代表性的避免死鎖的算法。在避免死鎖方法中允許進程動態地申請資源,但系統在進行資源分配之前,應先計算此次分配資源的安全性,若分配不會導致系統進入不安全狀態,則分配,否則等待。通過編寫一個模擬動態資源分配的銀行家算法程序,幫助學生進一步深入理解死鎖、產生死鎖的必要條件、安全狀態等重要概念,並掌握避免死鎖的具體實施方法。
三、實驗原理
3.1、銀行家算法中的數據結構
1)可利用資源向量Available
是個含有m個元素的數組,其中的每一個元素代表一類可利用的資源數目。如果Available[j]=K,則表示系統中現有Rj類資源K個。
Resources[] Available = new Resources[resKindNum];//系統總資源
2)最大需求矩陣Max
這是一個n×m的矩陣,它定義了系統中n個進程中的每一個進程對m類資源的最大需求。如果Max[i,j]=K,則表示進程i需要Rj類資源的最大數目爲K。
3)分配矩陣Allocation
這也是一個n×m的矩陣,它定義了系統中每一類資源當前已分配給每一進程的資源數。如果Allocation[i,j]=K,則表示進程i當前已分得Rj類資源的數目爲K。
4)需求矩陣Need。
這也是一個n×m的矩陣,用以表示每一個進程尚需的各類資源數。如果Need[i,j]=K,則表示進程i還需要Rj類資源K個,方能完成其任務。
Need[i,j]=Max[i,j]-Allocation[i,j]
//進程的數據結構
class PCB {
public String name;
public Resources[] max;//最大需求資源Max
public Resources[] allocation;//已分配資源Allocation
public Resources[] need;//需求資源Need
public boolean finish = false;//表示進程是否獲得足夠資源
public PCB(String name, Resources[] max, Resources[] allocation) {
this.name = name;
this.max = max;
this.allocation = allocation;
this.need = new Resources[max.length];
for (int i = 0; i < need.length; i++) {
this.need[i] = new Resources(max[i].name, max[i].num - allocation[i].num);
}
}
@Override
public String toString() {
return this.name +(this.finish ? "進程已得到足夠資源" : "需要等待");
}
}
3.2、銀行家算法
設Requesti是進程Pi的請求向量,如果Requesti[j]=K,表示進程Pi需要K個Rj類型的資源。當Pi發出資源請求後,系統按下述步驟進行檢查:
(1)如果Requesti[j]≤Need[i,j],便轉向步驟(2);否則認爲出錯,因爲它所需要的資源數已超過它所宣佈最大值。
(2)如果Requesti[j]≤Available[j],便轉向步驟(3);否則,表示尚無足夠資源,Pi須等待。
private boolean needWait(PCB pcb) {
//挨個判斷此時pcb這個進程所需要的每個資源,如果need大於系統當前可分配資源,就說明需要等待
for (int i = 0; i < this.work.length; i++) {
if (this.work[i].num < pcb.need[i].num) {
return true;
}
}
return false;
}
(3)系統試探着把資源分配給進程Pi,並修改下面數據結構中的數值:
Available[j]=Available[j]-Requesti[j];
Allocation[i,j]=Allocation[i,j]+Requesti[j];
Need[i,j]=Need[i,j]-Requesti[j];
系統執行安全性算法,檢查此次資源分配後,系統是否處於安全狀態。若安全,才正式將資源分配給進程Pi,以完成本次分配;否則,將本次的試探分配作廢,恢復原來的資源分配狀態,讓進程Pi等待。
//進行資源分配
public void resAllocation() {
//對進程進行循環資源分配,當所有進程都需要等待或者所有進程都爲安全狀態退出循環
for (int i = 0; !ifSafe() && !ifAllNeedWait(); i++) {
//實現循環
if (i == this.pcbs.length) {
i = 0;
}
//判斷當前這個進程是否已經獲得過足夠資源
if (pcbs[i].finish) {
continue;
}
//判斷當前這個進程是否需要等待
if (! needWait(pcbs[i])) {
//進行資源分配
mainOperation(pcbs[i]);
System.out.println(pcbs[i]);
System.out.println();
displayWorks();
}
}
System.out.println();
if (ifSafe()) {
System.out.println("系統處於安全狀態");
} else {
System.out.println("系統處於不安全狀態");
}
}
3.3、安全性算法
1)設置兩個向量:
工作向量Work: 它表示系統可提供給進程繼續運行所需的各類資源數目,它含有m個元素,在執行安全算法開始時,Work=Available;
工作向量Finish: 它表示系統是否有足夠的資源分配給進程,使之運行完成。開始時先做Finish[i]=false; 當有足夠資源分配給進程時, 再令Finish[i]=true。
2)從進程集合中找到一個能滿足下述條件的進程:
Finish[i]=false;
Need[i,j]≤Work[j];若找到,執行 (3),否則,執行 (4)
3)當進程Pi獲得資源後,可順利執行,直至完成,並釋放出分配給它的資源,故應執行:
Work[j]=Work[i]+Allocation[i,j];
Finish[i]=true;
go to step 2;
private void mainOperation(PCB pcb) {
//運行到這說明該進程可以得到足夠的資源,那麼直接將該進程已分配的資源放回到系統中
//並將finish改爲true
for (int i = 0; i < this.work.length; i++) {
this.work[i].num += pcb.allocation[i].num;
pcb.finish = true;
}
}
4)如果所有進程的Finish[i]=true都滿足, 則表示系統處於安全狀態;否則,系統處於不安全狀態
四、實現代碼
//系統資源的數據結構
class Resources {
public String name;
public int num;
public Resources(String name, int num) {
this.name = name;
this.num = num;
}
@Override
public String toString() {
return "資源"+ name + "有" + num;
}
}
//進程的數據結構
class PCB {
public String name;
public Resources[] max;//最大需求資源Max
public Resources[] allocation;//已分配資源Allocation
public Resources[] need;//需求資源Need
public boolean finish = false;//表示進程是否獲得足夠資源
public PCB(String name, Resources[] max, Resources[] allocation) {
this.name = name;
this.max = max;
this.allocation = allocation;
this.need = new Resources[max.length];
for (int i = 0; i < need.length; i++) {
this.need[i] = new Resources(max[i].name, max[i].num - allocation[i].num);
}
}
@Override
public String toString() {
return this.name +(this.finish ? "進程已得到足夠資源" : "需要等待");
}
}
public class BankerAlgorithm {
private Resources[] work;//當前可以資源
private PCB[] pcbs;//所有進程
public BankerAlgorithm(Resources[] Available, PCB[] pcbs) {
this.work = Available;//一開始可用資源與系統總資源是相同的
this.pcbs = pcbs;
//計算剩餘可用資源
actualWork();
}
private void actualWork() {
for (int i = 0; i < this.work.length; i++) {
//初始系統總資源減去已分配的資源就是當前可以利用的資源
this.work[i].num = this.work[i].num - pcbsAllRes(i);
}
}
//計算所有進程已分配的第i個資源總數
private int pcbsAllRes(int index) {
int sum = 0;
for ( PCB p : pcbs
) {
sum += p.allocation[index].num;
}
return sum;
}
//判斷是否爲安全狀態
private boolean ifSafe() {
for (PCB p : pcbs
) {
if (! p.finish) {
return false;
}
}
return true;
}
//進行資源分配
public void resAllocation() {
//對進程進行循環資源分配,當所有進程都需要等待或者所有進程都爲安全狀態退出循環
for (int i = 0; !ifSafe() && !ifAllNeedWait(); i++) {
//實現循環
if (i == this.pcbs.length) {
i = 0;
}
//判斷當前這個進程是否已經獲得過足夠資源
if (pcbs[i].finish) {
continue;
}
//判斷當前這個進程是否需要等待
if (! needWait(pcbs[i])) {
//進行資源分配
mainOperation(pcbs[i]);
System.out.println(pcbs[i]);
System.out.println();
displayWorks();
}
}
System.out.println();
if (ifSafe()) {
System.out.println("系統處於安全狀態");
} else {
System.out.println("系統處於不安全狀態");
}
}
private void displayWorks() {
System.out.println("此時系統可用資源爲:");
System.out.println("====================");
for (Resources r : this.work
) {
System.out.println(r);
}
System.out.println("====================");
}
private boolean ifAllNeedWait() {
for (PCB p : this.pcbs
) {
//如果該進程已經得到過足夠資源就不進行判斷
if (!p.finish) {
//如果該進程不需要等待就直接返回false
if (!needWait(p)) {
return false;
}
}
}
return true;
}
private void mainOperation(PCB pcb) {
//運行到這說明該進程可以得到足夠的資源,那麼直接將該進程已分配的資源放回到系統中
//並將finish改爲true
for (int i = 0; i < this.work.length; i++) {
this.work[i].num += pcb.allocation[i].num;
pcb.finish = true;
}
}
private boolean needWait(PCB pcb) {
//挨個判斷此時pcb這個進程所需要的每個資源,如果need大於系統當前可分配資源,就說明需要等待
for (int i = 0; i < this.work.length; i++) {
if (this.work[i].num < pcb.need[i].num) {
return true;
}
}
return false;
}
}
測試數據及結果
數據
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.print("輸入資源有幾種:");
int resKindNum = scan.nextInt();
Resources[] Available = new Resources[resKindNum];//系統總資源
System.out.println();
System.out.println("輸入每個系統資源名稱、系統資源數量");
for (int i = 0; i < Available.length; i++) {
System.out.println("初始化第" + (i +1) + "個資源");
System.out.println();
System.out.print("資源名稱:");
String name = scan.next();
System.out.println();
System.out.print("該資源數量:");
int num = scan.nextInt();
Available[i] = new Resources(name, num);
System.out.println();
System.out.println("第" + (i +1) + "個資源初始化完畢");
System.out.println("====================");
}
System.out.println();
System.out.println("系統資源初始化完畢,開始初始化進程");
System.out.println();
System.out.print("輸入進程個數:");
int pcbNums = scan.nextInt();
PCB[] pcbs = new PCB[pcbNums];
for (int i = 0; i < pcbNums; i++) {
System.out.println("初始化第" + (i +1) + "個進程");
System.out.println();
System.out.print("輸入進程名:");
String name = scan.next();
System.out.println();
System.out.print("輸入該進程最大需求資源:");
Resources[] max = new Resources[resKindNum];
int[] maxResNum = new int[resKindNum];
for (int j = 0; j < resKindNum; j++) {
maxResNum[j] = scan.nextInt();
}
for (int j = 0; j < max.length; j++) {
max[j] = new Resources(Available[j].name, maxResNum[j]);
}
System.out.println();
System.out.print("輸入該進程已分配資源數目:");
Resources[] allocation = new Resources[resKindNum];
int[] allocReesNum = new int[resKindNum];
for (int j = 0; j < resKindNum; j++) {
allocReesNum[j] = scan.nextInt();
}
for (int j = 0; j < allocation.length; j++) {
allocation[j] = new Resources(Available[j].name, allocReesNum[j]);
}
System.out.println();
//此時一個進程的所有需要的東西都已輸入完畢
pcbs[i] = new PCB(name, max, allocation);
System.out.println("第" + (i +1) + "個進程初始化完畢");
System.out.println("====================");
}
System.out.println();
System.out.println("========所有進程初始化完畢,開始資源分配========");
System.out.println();
boolean key = true;
while (key) {
BetterBankerAlgorithm bankerAlgorithm = new BetterBankerAlgorithm(Available, pcbs);
bankerAlgorithm.resAllocation();
System.out.println();
System.out.println("是否需要再次申請資源輸入: y or n ");
char ch = scan.next().charAt(0);
if (ch == 'n' || ch == 'N') {
key = false;
} else {
System.out.print("輸入要申請資源的進程名:");
String name = scan.next();
System.out.println();
System.out.print("輸入要申請資源的數量:");
int[] res = new int[resKindNum];
for (int i = 0; i < resKindNum; i++) {
res[i] = scan.nextInt();
}
System.out.println();
for (PCB p : pcbs
) {
p.finish = false;
if (p.name.equals(name)) {
for (int i = 0; i < p.allocation.length; i++) {
p.allocation[i].num += res[i];
}
}
}
System.out.println();
System.out.println("========再次申請資源完畢,開始資源分配========");
System.out.println();
}
}
}
}
結果
輸入資源有幾種:4
輸入每個系統資源名稱、系統資源數量
初始化第1個資源
資源名稱:R1
該資源數量:6
第1個資源初始化完畢
====================
初始化第2個資源
資源名稱:R2
該資源數量:7
第2個資源初始化完畢
====================
初始化第3個資源
資源名稱:R3
該資源數量:12
第3個資源初始化完畢
====================
初始化第4個資源
資源名稱:R4
該資源數量:12
第4個資源初始化完畢
====================
系統資源初始化完畢,開始初始化進程
輸入進程個數:5
初始化第1個進程
輸入進程名:P0
輸入該進程最大需求資源:0 0 1 2
輸入該進程已分配資源數目:0 0 1 2
第1個進程初始化完畢
====================
初始化第2個進程
輸入進程名:P1
輸入該進程最大需求資源:2 7 5 0
輸入該進程已分配資源數目:2 0 0 0
第2個進程初始化完畢
====================
初始化第3個進程
輸入進程名:P2
輸入該進程最大需求資源:6 6 5 6
輸入該進程已分配資源數目:0 0 3 4
第3個進程初始化完畢
====================
初始化第4個進程
輸入進程名:P3
輸入該進程最大需求資源:4 3 5 6
輸入該進程已分配資源數目:2 3 5 4
第4個進程初始化完畢
====================
初始化第5個進程
輸入進程名:P4
輸入該進程最大需求資源:0 6 5 2
輸入該進程已分配資源數目:0 3 3 2
第5個進程初始化完畢
====================
========所有進程初始化完畢,開始資源分配========
P0進程已得到足夠資源
此時系統可用資源爲:
====================
資源R1有2
資源R2有1
資源R3有1
資源R4有2
====================
P3進程已得到足夠資源
此時系統可用資源爲:
====================
資源R1有4
資源R2有4
資源R3有6
資源R4有6
====================
P4進程已得到足夠資源
此時系統可用資源爲:
====================
資源R1有4
資源R2有7
資源R3有9
資源R4有8
====================
P1進程已得到足夠資源
此時系統可用資源爲:
====================
資源R1有6
資源R2有7
資源R3有9
資源R4有8
====================
P2進程已得到足夠資源
此時系統可用資源爲:
====================
資源R1有6
資源R2有7
資源R3有12
資源R4有12
====================
系統處於安全狀態
是否需要再次申請資源輸入: y or n
Y
輸入要申請資源的進程名:P2
輸入要申請資源的數量:0 1 0 0
========再次申請資源完畢,開始資源分配========
P0進程已得到足夠資源
此時系統可用資源爲:
====================
資源R1有2
資源R2有0
資源R3有1
資源R4有2
====================
P3進程已得到足夠資源
此時系統可用資源爲:
====================
資源R1有4
資源R2有3
資源R3有6
資源R4有6
====================
P4進程已得到足夠資源
此時系統可用資源爲:
====================
資源R1有4
資源R2有6
資源R3有9
資源R4有8
====================
系統處於不安全狀態
是否需要再次申請資源輸入: y or n
N