前言
銀行家算法,是我們OS課上的一個非常重要的知識點,感覺可以說是必考題了,但是考試嘛,考過了以後不用就會忘,每次都要重新復(yu)習一遍,又非常麻煩,正好前段時間有機會實現了一遍,趕緊總結下,避免以後又忘了。
正文
銀行家算法簡介
銀行家算法(Banker’s Algorithm)是一個避免死鎖(Deadlock)的著名算法,是由艾茲格·迪傑斯特拉在1965年爲T.H.E系統設計的一種避免死結產生的演算法。它以銀行借貸系統的分配策略爲基礎,判斷並保證系統的安全運行。
(來自wiki)
這裏的重點是避免!!! 避免!!! 避免!!!
針對死鎖這種坑爹的情況有預防和避免兩種大的解決思路,之前總是傻傻分不清楚。這裏我們還是通過一個生動的例子來解釋吧。
女朋友:康康啊,預防感冒,衝杯板x根吧。
康康:好滴。
女朋友:康康啊,出門繫上我給你織的圍巾吧,避免感冒。
康康:好幾。
感受到預防和避免的差異了嘛,預防就是提前做好準備,而避免則是在實際操作中小心翼翼。
回到死鎖,預防死鎖就是破壞死鎖的四個必要條件之一,而避免死鎖則是在進程運行過程中通過一些手段來避免死鎖。
算法詳解
其實銀行家算法非常簡單。
系統維護了一張所有進程的資源表。進程對每種資源的總共需求數,當前已分配的資源數,還需要的資源數。
假設系統初始狀態爲S0,在每次請求資源(並且這次請求合法)時,會假設爲進程分配需要的資源,這時系統進入狀態S1*,判斷這個假設狀態是否爲安全的,如果是安全的,纔會進行真正分配,系統進入S1狀態;否則系統不會進行資源分配。
判斷系統此時狀態是否安全的算法也很簡單。
就是假設所有進程能否按照某種順序運行(這裏的運行就是 請求資源->工作->釋放資源 這個過程)。
如果存在這樣一個進程運行序列,就是安全的。反之則不安全。
源碼分析
數據結構
const int process_nums = 5; // 進程數
const int resource_nums = 3; //資源種類數
//進程的兩種狀態
enum {
RUNNING = 0,
SLEEP
};
//模擬的進程 只有pid和state兩個成員,默認爲SLEEP狀態
struct Process
{
Process(int id):pid(id), state(SLEEP){}
int pid;
int state;
};
vector<int> available; //一維數組,記錄每種資源的現有(空閒)個數
vector<vector<int>> max_request, allocation, need,request;
//max_request 每個進程對每種資源的總共需求數 二維數組
//allocation 每個進程對每種資源的當前分配數 二維數組
//need 每個進程對每種資源的當前分配數(need[i][j] = max_request[i][j] - allocation[i][j]) 二維數組
vector<Process> process;
//進程組 每個進程的pid = index
模擬流程
while(isSomeProcessNeedResource(need)){
//模擬調度,讓一個進程開始運行
now_running_process = scheProcess(need);
process[now_running_process].state = RUNNING;
//獲取進程此次運行,對於每種資源的需求數
getRequest(now_running_process, request);
//判斷此次需求是否合法
for(int i = 0; i < resource_nums; i++){
//此次需求大於need,說明需求錯誤
if(request[now_running_process][i] > need[now_running_process][i]){
cout << "request error" << endl;
return -1;
}
//此次需求大於available,資源數量不夠,讓進程阻塞 if(request[now_running_process][i] > available[i]){
process[now_running_process].state = SLEEP;
break;
}
}
//如果需求合法,進入分配階段
if(process[now_running_process].state == RUNNING){
//(1)假設分配
for(int i = 0; i < resource_nums; i++){
available[i] -= request[now_running_process][i];
allocation[now_running_process][i] += request[now_running_process][i];
need[now_running_process][i] -= request[now_running_process][i];
}
print(available, max_request, need ,allocation);
//判斷經過分配後,整個系統是否處於安全狀態
if(judgeSecurity(available, need, process, allocation) == -1){
//系統不安全,將假設分配的資源還給OS
for(int i = 0; i < resource_nums; i++){
available[i] += request[now_running_process][i];
allocation[now_running_process][i] -= request[now_running_process][i];
need[now_running_process][i] += request[now_running_process][i];
}
cout << "now is not security" << endl;
} else{
cout << "now is security" << endl;
}
process[now_running_process].state = SLEEP;
}
}
核心算法:安全性檢驗
判斷系統當前狀態是否安全。
int judgeSecurity(const vector<int>& available,
const vector<vector<int>>& need,
const vector<Process>& process,
const vector<vector<int>> &allocation)
{
vector<int> work(available);//現有的每種資源空閒數
vector<bool> finish(process_nums, false);//標誌數組,判斷進程是否完成工作
vector<int> security_list;
int p_nums = process_nums;
//當需要資源的進程數不爲0
while(p_nums){
int s = p_nums;
for(int i = 0; i < process_nums; i++){
//如果進程還沒有完成所有工作,並且它需要的資源數小於現有的空閒資源數,則可以給它分配資源
if(finish[i] == false && judgeNeed(need[i], work)){
//分配之後則認爲進程已經完成所有工作
finish[i] = true;
p_nums--;
security_list.push_back(i);
//將進程之前佔有的資源釋放
for(int j = 0; j < resource_nums; j++)
work[j] += allocation[i][j];
}
}
//如果沒有進程能被分配給資源,說明會產生死鎖,系統處於不安全狀態
if(s == p_nums)
return -1;
}
//輸出當前狀態存在的安全序列
cout << "security_list is :"<< endl;
for(auto i : security_list)
cout << "p" << i << "->";
cout << "end" << endl;
return 0;
}