1.數據結構
- 可利用的資源向量Available:一個含有m個元素的數組,其中每一個元素代表一類可利擁的資源數目,其初始值是系統中所配置的該類全部可用資源數目,其數值隨該類資源的分配改變而改變。如果Available[j]=K,則表示系統中現有Rj類資源K個。
- 最大需求矩陣Max:一個n×m的矩陣,它定義了系統中n個進程中的每一個進程對m類資源的最大需求。如果Max[i,j]=K,則表示進程i需要Rj類資源的最大數目為K。
- 分配矩陣Allocation:一個n×m的矩陣,它定義了系統中每一類資源當前已分配給每一進程的資源數。如果Allocation[i,j]=K,則表示進程i當前已分得Rj類資源的數目為K。
- 需求矩陣Need:一個n×m的矩陣,用以表示每一個進程尚需的各類資源數。如果Need[i,j]=K,則表示進程i還需要Rj類資源K個方能完成其任務。
Need[i,j]=Max[i,j]-Allocation[i,j]
2.銀行家算法
在避免死鎖的方法中,所施加的限制條件較弱,有可能獲得令人滿意的系統性能。在該方法中把系統的狀態分為安全狀態和不安全狀態,只要能使系統始終都處於安全狀態,便可以避免發生死鎖。銀行家算法的基本思想是分配資源之前,判斷系統是否是安全的;若是,才分配。它是最具有代表性的避免死鎖的算法。
設進程cusneed提出請求REQUEST [i],則銀行家算法按如下規則進行判斷。
(1)如果REQUEST [cusneed] [i]<= NEED[cusneed][i],則轉(2);否則,出錯。
(2)如果REQUEST [cusneed] [i]<= AVAILABLE[i],則轉(3);否則,等待。
(3)系統試探分配資源,修改相關數據:
AVAILABLE[i]-=REQUEST[cusneed][i];
ALLOCATION[cusneed][i]+=REQUEST[cusneed][i];
NEED[cusneed][i]-=REQUEST[cusneed][i];
(4)系統執行安全性檢查,如安全,則分配成立;否則試探險性分配作廢,系統恢復原狀,進程等待。
3.安全性算法
(1)設置兩個工作向量Work=AVAILABLE;FINISH
(2)從進程集合中找到一個滿足下述條件的進程,
FINISH==false;
NEED<=Work;
如找到,執行(3);否則,執行(4)
(3)設進程獲得資源,可順利執行,直至完成,從而釋放資源。
Work=Work+ALLOCATION;
Finish=true;
GOTO 2
(4)如所有的進程Finish= true,則表示安全;否則系統不安全。
主要代碼:
安全性檢測:
public void allocation(){ flag_i.clear(); for (int i = 0; i < this.processes_Size ; i++) { Finish[i] = false; } for (int i = 0; i < this.Resources_Size ; i++) { Work[0][i] = AvailableTmp[0][i]; } int count = 0; int flag = 0; //flag_i中的個數 while (count < this.processes_Size){ for (int i = 0; i < this.processes_Size ; i++) { if(flag_i.contains(i)){ continue; }else { int k = 0; while (k < this.Resources_Size){ if(NeedTmp[i][k] <= Work[count][k] && (this.Finish[count]==false)){ k++; }else { k = this.Resources_Size+1; } } if(k == this.Resources_Size){ flag_i.add(i); flag++; break; //每次添加一個 } } } // //每走一遍for循環應該找到一個,才能往下執行 if((count+1) == flag){ for (int i = 0; i < this.Resources_Size; i++) { Work_All[count][i] = Work[count][i] + AllocationTmp[(int) flag_i.get(count)][i]; } this.Finish[count] = true; count++; //賦值 for (int i = 0; i < this.Resources_Size; i++) { Work[count][i] = Work_All[count - 1][i]; } } else { count++; System.out.println("第"+count+"次安全性檢測失敗!"); break; } if(Finish[count-1] == false){ break; } } //跳出循環如果有進程數個值,說明每個進程都能滿足,將試分配的值真實分配 if(flag_i.size() == this.processes_Size){ for (int i = 0; i < this.processes_Size; i++) { for (int j = 0; j < this.Resources_Size ; j++) { Allocation[i][j] =AllocationTmp[i][j]; Need[i][j] = NeedTmp[i][j]; } } for (int i = 0; i < this.Resources_Size; i++) { Available[0][i] = AvailableTmp[0][i]; } showResult(); System.out.println("*********************************"); show(); }else { if(flag_i.size() == 0){ System.out.println("不滿足任何進程的需求!"); System.out.println("無安全序列!"); System.out.println("******************************"); show(); }else { System.out.println("無安全序列!"); System.out.println("*****************************"); show(); } } }
銀行家分配部分:
private void requset() { copy(); System.out.println("請輸入要請求資源的進程號:"); String name = scanner.next(); int putInto = -1; //判斷輸入的是幾號進程 for (int i = 0; i < this.processes_Size; i++) { if (name.equals(processes[i])){ putInto = i; } } //如果輸入的在進程序列內不存在 if(putInto == -1){ System.out.println("非法輸入!"); return; } System.out.println(); System.out.println("請輸入再次申請的資源大小:"); int[] num = new int[this.Resources_Size]; //輸入的request值 for (int i = 0; i < this.Resources_Size; i++) { num[i] = scanner.nextInt(); } int k = 0; for (int i = 0; i < this.Resources_Size; i++) { if ((num[i] <= Need[putInto][i]) && (num[i] <= Available[0][i])) { k++; } else { if((num[i] > Need[putInto][i])) { System.out.println("申請大於需要的進程!"); System.out.println("***************************"); show(); return; } if(num[i] > Available[0][i]){ System.out.println("資源不足!"); System.out.println("***************************"); show(); return; } } } //跳出說明滿足要求嘗試分配資源 if(k == this.Resources_Size){ for (int j = 0; j < this.Resources_Size; j++) { NeedTmp[putInto][j] = NeedTmp[putInto][j] - num[j]; AllocationTmp[putInto][j] = AllocationTmp[putInto][j] + num[j]; AvailableTmp[0][j] = AvailableTmp[0][j] - num[j]; } } allocation(); }
但是遇到的問題是,當滿足銀行家算法但是不滿足安全性算法時,怎么將銀行家預分配的再次還給初始分配前的值,最終采用臨時的副本數組,每次安全性算法都是對副本操作,當滿足時,才將原數組改變,然后將其輸出,當然還有當一個就是一個進程的所需要的資源已經全部得到,此時應該將其刪除序列表,並且將其拿到的資源全部還給系統,以便於其他進程的申請。
刪除進程(已經獲取到了全部所需要的資源):
private void resReturn(){ int count = 0; int num = 0; while (count < processes_Size) { for (int i = 0; i < this.Resources_Size; i++) { if (Need[count][i] == 0){ num++; } } if(num == Resources_Size){ for (int i = 0; i < this.Resources_Size ; i++) { Available[0][i] = Allocation[count][i]+Available[0][i]; } for (int i = 0; i < this.processes_Size; i++) { for (int j = 0; j < this.Resources_Size; j++) { if(i < count){ Need[i][j] = Need[i][j]; Allocation[i][j] = Allocation[i][j]; processes[i] = processes[i]; }else { Need[i][j] = Need[i+1][j]; Allocation[i][j] = Allocation[i+1][j]; processes[i] = processes[i+1]; } } } processes_Size--; } num = 0; count++; } }
測試用例:
申請資源:
當某個進程所需要的資源全部得到的情況如圖: