银行家算法详解
銀行家算法詳解
文章目錄
- 銀行家算法詳解
- 一、銀行家算法詳解
- 1.背景簡介
- 2.安全序列
- 3.實現方法:
- 4.檢查算法描述
- 5.案例
- 二、簡單實現
- 三、總結
一、銀行家算法詳解
- 銀行家算法是一種避免死鎖的方法
1.背景簡介
在銀行中,客戶申請貸款的數量是有限的,每個客戶在第一次申請貸款時要聲明完成該項目所需的最大資金量,在滿足所有貸款要求時,客戶應及時歸還。銀行家在客戶申請的貸款數量不超過自己擁有的最大值時,都應盡量滿足客戶的需要。在這樣的描述中,銀行家就好比操作系統,資金就是資源,客戶就相當于要申請資源的進程。
銀行家算法是一種最有代表性的避免死鎖的算法。在避免死鎖方法中允許進程動態地申請資源,但系統在進行資源分配之前,應先計算此次分配資源的安全性,若分配不會導致系統進入不安全狀態,則分配,否則等待。
2.安全序列
- 安全序列是指某個進程序列{P1,…,Pn}是安全的,即對于每一個進程Pi(1≤i≤n),它以后尚需要的資源量不超過系統當前剩余資源量與所有進程Pj(j < i)當前占有資源量之和。(即在分配過程中,不會出現某一進程后續需要的資源量比其他所有進程及當前剩余資源量總和還大的情況)
注:存在安全序列則系統是安全的,如果不存在則系統不安全,但不安全狀態不一定引起死鎖。
3.實現方法:
為保證資金的安全,銀行家規定:
- (1) 當一個顧客對資金的最大需求量不超過銀行家現有的資金時就可接納該顧客;
(即當資源池中剩余的可利用資源 >=線程還需要的資源時,就可以將可利用資源分配給此線程) - (2) 顧客可以分期貸款,但貸款的總數不能超過最大需求量;
(線程可以請求分配資源,但是請求的資源總數不能超過資源池中剩余的可利用資源) - (3) 當銀行家現有的資金不能滿足顧客尚需的貸款數額時,對顧客的貸款可推遲支付,但總能使顧客在有限的時間里得到貸款;
(當線程池中的資源暫時不滿足當前的線程所需時,將此線程先暫時擱置,先將資源分配給能夠滿足的需求的其他線程,等到線程池中的資源足夠滿足先前擱置的線程時,在將資源分配給擱置的線程) - (4) 當顧客得到所需的全部資金后,一定能在有限的時間里歸還所有的資金。
(當線程拿到所需要的所有資源,運行結束后,將自身所有的資源放回資源池中)
當一個進程申請使用資源的時候,銀行家算法通過先 試探 分配給該進程資源,然后通過安全性算法判斷給該進程分配資源后的系統是否處于安全狀態,若系統處于不安全狀態,則試探分配作廢,讓該進程繼續等待;
系統給當前進程分配資源時,先檢查是否安全:
在滿足當前的進程X資源申請后,是否還能有足夠的資源去滿足下一個距最大資源需求最近的進程(如某進程最大需要5個單位資源,已擁有1個,還尚需4個),若可以滿足,則繼續檢查下一個距最大資源需求最近的進程,若均能滿足所有進程,則表示為安全,可以允許給當前進程X分配其所需的資源申請,否則讓該進程X進入等待。
- 對于當前進程Pi X
- (1) 檢查if( Request[ i ][ j ]<=Need[ i ][ j ] ) goto (2)
else error(“進程 i 對資源的申請量大于其說明的最大值 ”); - (2) 檢查 if ( Request[ i ][ j ]<=Available[ j ] ) goto (3)
else wait() ; /注意是等待!即在對后續進程的需求資源判斷中,若出現不符合的則安全檢查結束,當前進程進入等待/ - (3) 系統試探地把資源分給Pi 并修改各項屬性值 (具體是否成立,則根據安全檢查的結果)
- (4) 安全檢查,若檢查結果為安全,則(3)中執行有效,否則分配作廢,使該Pi進程進入等待
4.檢查算法描述
- 向量Free[ j ]表示系統可分配給各進程的Rj類資源數目,初始與當前Available等值
- 向量Finish[ i ]表示進程Pi在此次檢查中是否被滿足,初始均為false 當有足有資源可分配給進程時,
- 1) 從進程隊列中找一個能滿足下述條件的進程Pi
- 2) 當Pi獲得資源后,認為Pi完成,釋放資源
(銀行家算法在避免死鎖角度上非常有效,但是需要在進程運行前就知道其所需資源的最大值,且進程數也通常不是固定的,因此使用有限,但從思想上可以提供了解,可以轉換地應用在其他地方)
假設資源P1申請資源,銀行家算法先試探的分配給它(當然先要看看當前資源池中的資源數量夠不夠),若申請的資源數量小于等于Available,然后接著判斷分配給P1后剩余的資源,能不能使進程隊列的某個進程執行完畢,若沒有進程可執行完畢,則系統處于不安全狀態(即此時沒有一個進程能夠完成并釋放資源,隨時間推移,系統終將處于死鎖狀態)。
若有進程可執行完畢,則假設回收已分配給它的資源(剩余資源數量增加),把這個進程標記為可完成,并繼續判斷隊列中的其它進程,若所有進程都可執行完畢,則系統處于安全狀態,并根據可完成進程的分配順序生成安全序列
如此就可避免系統存在潛在死鎖的風險。
5.案例
有5個進程{P1,P2,P3,P4,P5} 。4類資源{R1,R2,R3,R4} 各自數量為6、3、4、2
T0時刻各進程分配資源情況如下
T0時刻為安全狀態,存在安全序列{P4,P1,P2,P3,P5} 如下:
二、簡單實現
#include <iostream> #include <cstdio> #include <cstring> using namespace std;const int maxpro = 100; //最大進程數 const int maxres = 100; //最大資源數int pro; //進程數 int res; //資源數int request[maxres];//進程請求資源數目 //int R[maxres]; //總資源 int V[maxres]; //可提供 int C[maxpro][maxres]; //總需求 int A[maxpro][maxres]; //已分配 int vis[maxpro]; //表示第i個進程是否已分配資源,1表示已分配 int path[maxpro]; //路徑//安全狀態判斷 bool safe() {int curV[maxres]; //目前可提供資源for(int i = 0; i < res; i++)curV[i] = V[i];memset(vis, 0, sizeof(vis));int flag = 1;for(int i1 = 0; i1 < pro; i1++) {int i;for(i = 0; i < pro; i++) {if(vis[i] == 1) continue;int flagpro = 1; //0表示未找到合適的進程for(int j = 0; j < res; j++) {if(C[i][j] - A[i][j] > curV[j]) {flagpro = 0; break;}}if(flagpro) {path[i1] = i;vis[i] = 1;for(int k = 0; k < res; k++)curV[k] += A[i][k];break;}}if(i == pro) {flag = 0;}}return flag == 1; }void print() {cout << endl << "顯示當前狀態" << endl;cout << "總需求矩陣C" << endl;for(int i = 0; i < pro; i++) {for(int j = 0; j < res; j++) {printf("%2d ", C[i][j]);}cout << endl;}cout << "已分配矩陣A" << endl;for(int i = 0; i < pro; i++) {for(int j = 0; j < res; j++) {printf("%2d ", A[i][j]);}cout << endl;}cout << "需求矩陣N (C-A)" << endl;for(int i = 0; i < pro; i++) {for(int j = 0; j < res; j++) {printf("%2d ", C[i][j] - A[i][j]);}cout << endl;}/* cout << "總資源向量R" << endl;for(int i = 0; i < res; i++)cout << R[i] << ' ';cout << endl;*/cout << "可提供資源向量V" << endl;for(int i = 0; i < res; i++)cout << V[i] << ' ';cout << endl << endl; }void bank() {while(true) {cout << endl << "請求資源輸入1,顯示當前狀態輸入2, 結束輸入3" << endl;int k;cin >> k;if(k == 3) break;else if(k == 2) {print(); continue;}cout << "請輸入請求資源的進程編號, 進程號為0 - " << pro - 1 << endl;int proindex;cin >> proindex;cout << "請輸入此進程每個資源需求數目" << endl;for(int i = 0; i < res; i++)cin >> request[i];//檢查該進程所需要的資源是否已超過它所宣布的最大值int flag = 1; //flag為1表示沒超過,為0表示超過for(int i = 0; i < res; i++) {if(request[i] + A[proindex][i] > C[proindex][i])flag = 0;}if(flag == 0) {cout << "資源請求失敗,該進程所需要的資源已超過總資源的最大值" << endl;continue;}//檢查系統當前是否有足夠資源滿足該進程的請求flag = 1; //flag為1有足夠資源,為0表示沒有for(int i = 0; i < res; i++) {if(request[i] > V[i])flag = 0;}if(flag == 0) {cout << "資源請求失敗,系統當前沒有有足夠資源滿足該進程的請求" << endl;continue;}//嘗試分配資源給該進程,得到新的狀態for(int i = 0; i < res; i++) {A[proindex][i] += request[i]; //已分配資源矩陣A更新V[i] -= request[i]; //可提供資源向量V更新}//執行安全性算法,若該新狀態是安全的,則分配完成;若新狀態是不安全的,則恢復原狀態,阻塞該進程if(safe()) {cout << "資源分配成功" << endl;cout << "安全路徑是:";for(int i = 0; i < pro; i++){cout << path[i] << " ";}cout << endl;for(int i = 0; i < pro; i++) {int j;for(j = 0; j < res; j++) {if(A[i][j] != C[i][j])break;}if(j == res){for(j = 0; j < res; j++) {V[j] += A[i][j];A[i][j] = 0;}}}}else {cout << "該狀態不安全,資源分配失敗" << endl;for(int i = 0; i < res; i++) {A[proindex][i] -= request[i]; //已分配資源矩陣A更新V[i] += request[i]; //可提供資源向量V更新}}} }int main() {cout << "請輸入總資源數: " << endl;cin >> res;cout << "請輸入總進程數: " << endl;cin >> pro; /*cout << "請分別輸入每個資源的數目(R向量),目前有" << res << "個資源" << endl;for(int i = 0; i < res; i++)cin >> R[i];*/cout << "請分別輸入每個資源的已分配數目(V向量),目前有" << res << "個資源" << endl;for(int i = 0; i< res; i++)cin >> V[i];cout << "請輸入總需求矩陣C,共有" << res << "個資源," << pro << "個進程" << endl;cout << "格式: 每行輸入單個進程的總需求資源數目, 輸入" << pro << "行" << endl;for(int i = 0; i < pro; i++)for(int j = 0 ; j < res; j++)cin >> C[i][j];cout << "請輸入已分配矩陣A,共有" << res << "個資源," << pro << "個進程" << endl;cout << "格式: 每行輸入單個進程的已分配資源數目, 輸入" << pro << "行" << endl;for(int i = 0; i < pro; i++)for(int j = 0 ; j < res; j++)cin >> A[i][j];bank();return 0; }三、總結
- 死鎖避免的基本思想是動態地檢測資源分配狀態,以確保循環等待條件不成立,從而確保系統處于安全狀態。所謂安全狀態是指:如果系統能按某個順序為每個進程分配資源(不超過其最大值),那么系統狀態是安全的,換句話說就是,如果存在一個安全序列,那么系統處于安全狀態。
- 資源分配圖算法和銀行家算法是兩種經典的死鎖避免的算法,其可以確保系統始終處于安全狀態。
- 其中,資源分配圖算法應用場景為每種資源類型只有一個實例(申請邊,分配邊,需求邊,不形成環才允許分配),而銀行家算法應用于每種資源類型可以有多個實例的場景。
總結
- 上一篇: 分段翻转链表
- 下一篇: 力扣--统计全1子矩阵