銀行家算法


銀行家算法的實現

以下部分內容來自百度百科:銀行家算法

題目描述:

  •   銀行家算法(Banker’s Algorithm)是一個避免死鎖(Deadlock)的著名算法,是由艾茲格·迪傑斯特拉在1965年為T.H.E系統設計的一種避免死鎖產生的算法。它以銀行借貸系統的分配策略為基礎,判斷並保證系統的安全運行。
      在銀行中,客戶申請貸款的數量是有限的,每個客戶在第一次申請貸款時要聲明完成該項目所需的最大資金量,在滿足所有貸款要求時,客戶應及時歸還。銀行家在客戶申請的貸款數量不超過自己擁有的最大值時,都應盡量滿足客戶的需要。在這樣的描述中,銀行家就好比操作系統,資金就是資源,客戶就相當於要申請資源的進程。

  銀行家算法是一種最有代表性的避免死鎖的算法。在避免死鎖方法中允許進程動態地申請資源,但系統在進行資源分配之前,應先計算此次分配資源的安全性,若分配不會導致系統進入不安全狀態,則分配,否則等待。為實現銀行家算法,系統必須設置若干數據結構。
  操作系統安全狀態和不安全狀態,,等價於操作系統是否存在一個安全序列。安全序列是指一個進程序列{P1,…,Pn}是安全的,即對於每一個進程Pi(1≤i≤n),它以后尚需要的資源量不超過系統當前剩余資源量與所有進程Pj (j < i )當前占有資源量之和。

數據結構
1)可利用資源向量Available
是個含有m個元素的數組,其中的每一個元素代表一類可利用的資源數目。如果Available[j]=K,則表示系統中現有Rj類資源K個。
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],因此Need,Max,Allocation,三者只需要知道兩個即可。在這里插入圖片描述

算法原理:
  我們可以把操作系統看作是銀行家,操作系統管理的資源相當於銀行家管理的資金,進程向操作系統請求分配資源相當於用戶向銀行家貸款。
為保證資金的安全,銀行家規定:
(1) 當一個顧客對資金的最大需求量不超過銀行家現有的資金時就可接納該顧客;
(2) 顧客可以分期貸款,但貸款的總數不能超過最大需求量;
(3) 當銀行家現有的資金不能滿足顧客尚需的貸款數額時,對顧客的貸款可推遲支付,但總能使顧客在有限的時間里得到貸款;
(4) 當顧客得到所需的全部資金后,一定能在有限的時間里歸還所有的資金.
操作系統按照銀行家制定的規則為進程分配資源,當進程首次申請資源時,要測試該進程對資源的最大需求量,如果系統現存的資源可以滿足它的最大需求量則按當前的申請量分配資源,否則就推遲分配。當進程在執行中繼續申請資源時,先測試該進程本次申請的資源數是否超過了該資源所剩余的總量。若超過則拒絕分配資源,若能滿足則按當前的申請量分配資源,否則也要推遲分配。

算法實現:
初始化

由用戶輸入數據,分別對可利用資源向量矩陣AVAILABLE、分配矩ALLOCATION、需求矩陣NEED賦值。

具體過程:

銀行家算法的基本思想是分配資源之前,判斷系統是否是安全的;若是,才分配。它是最具有代表性的避免死鎖的算法。在該方法中把系統的狀態分為安全狀態和不安全狀態,只要能使系統始終都處於安全狀態,便可以避免發生死鎖。
設進程q提出請求REQUEST [i],則銀行家算法按如下規則進行判斷。
(1)如果REQUEST [q] [i]<= NEED[q][i],則轉(2);否則,出錯。
(2)如果REQUEST [q] [i]<= AVAILABLE[i],則轉(3);否則,等待。
(3)系統試探分配資源,修改相關數據:
AVAILABLE[i]-=REQUEST[q][i];
ALLOCATION[q][i]+=REQUEST[q][i];
NEED[q][i]-=REQUEST[q][i];
(4)系統執行安全性檢查,如安全,則分配成立;否則試探險性分配作廢,系統恢復原狀,進程等待。
在這里插入圖片描述

安全性檢查算法

(1)設置兩個工作向量Work=AVAILABLE;FINISH
(2)從進程集合中找到一個滿足下述條件的進程,
FINISH==false;
NEED<=Work;
如找到,執行(3);否則,執行(4)
(3)設進程獲得資源,可順利執行,直至完成,從而釋放資源。
Work=Work+ALLOCATION;
Finish=true;
GOTO 2
(4)如所有的進程Finish= true,則表示安全;否則系統不安全。
來自王道考研

尋找安全序列時需要注意的問題:

在安全檢查中尋找符合條件的進程時,不能僅用一層循環來實現對所有進程的遍歷,否則無法過濾錯誤的序列。
應該采用類似與DFS的方式遍歷每一種可能的序列,不斷的”試錯“,找到錯誤的序列就主動回退尋找下一條序列。

具體方法:
  1. 每次從tem+1位置開始遍歷,判斷是否有符合條件(work<need[p]且Finish[j] == 0)的進程p

  2. 如果有符合的進程就執行:

  • Finish[p] = 1;
  • Cstack.push§;
  • Work[i] += Alloc[flag0][i] //進程釋放資源
  • tem = 0;//有元素入棧后 tem=1 下次從頭開始掃描
  1. 如果沒有符合的進程並且進程已經全部進入安全序列則:
  • return 1;//如果已經全部進入安全序列 返回1
  • 返回對符合條件進程的判斷步驟
  1. 如果沒有符合的進程並且進程沒有全部進入安全序列並且棧不空則:
  • tem = Cstack.top();
  • Finish[tem] = 0;
  • Work[i] -= Alloc[tem][i];//回歸進程釋放資源
  • Cstack.pop();
  • 返回對符合條件進程的判斷步驟
  1. 如果沒有符合的進程並且進程沒有全部進入安全序列並且棧為空則:
  • return 0;
    銀行家算法流程圖:

銀行家算法的C++實現:

#include <iostream>
#include <stack>
using namespace std;
#define n 5//進程個數
#define m 3//資源種類
bool Finish[n+1];//安全序列 
stack<int> Cstack;
//int Available[m + 1], Alloc[n + 1][m + 1], Need[n + 1][m + 1];
int Available[m+1] = { 0,2,3,3 };
int Alloc[n+1][m+1] = {0,0,0,0,     0,2,1,2,    0,4,0,2,   0,3,0,5,     0,2,0,4,   0,3,1,4 };
int Need[n+1][m+1] = { 0,0,0,0,      0,3,4,7,     0,1,3,4,     0,0,0,3,    0, 2,2,1,     0,1,1,0};
/*幾組測試數據 2 0 3 4 無法滿足,因為請求資源大於系統現有的資源數 4 1 0 1 4 2 3 5 1 1 2 0 1 安全檢查無法滿足,該進程被阻塞: 3 0 0 2 3 2 4 5 1 */



void StackPrint(stack<int> &a) { // 用於遞歸的輸出一個棧的信息
    if (a.empty())
        return;
    int A = a.top();
    a.pop();
    StackPrint(a);
    cout << A << "-->";
}

int SafeCheck() {
    for (int i = 1; i <= n; i++)
        Finish[i] = 0;//安全序列,0表示i號進程不在其中
    int Work[m+1];
    for (int i = 1; i <= m; i++)
        Work[i] = Available[i];

    int tem = 0;
    while (1) {
        int flag0 = 0;//是否存在
        int flag1;//該進程work可滿足(work<need[p])的p

        for (int j = tem+1; j <= n; j++) {
            flag1 = 1;
            for (int i = 1; i <= m; i++)
                if (Need[j][i] > Work[i])
                    flag1 = 0;
            if (Finish[j] == 0 && flag1 == 1) {
                flag0 = j;
                break;
            }
        }
        if (flag0 != 0) {
            Finish[flag0] = 1;//進程進入安全序列
            Cstack.push(flag0);
            tem = 0;//有元素入棧后 tem=1 下次從頭開始掃描
            for (int i = 1; i <= m; i++)
                Work[i] += Alloc[flag0][i];//進程釋放資源
        }
        else {
            if (Cstack.size() == n)
                return 1;//如果已經全部進入安全序列 返回1
            if (!Cstack.empty()) {
                tem = Cstack.top();
                Finish[tem] = 0;
                for (int i = 1; i <= m; i++)
                    Work[i] -= Alloc[tem][i];//回歸進程釋放資源
                Cstack.pop();
            }
            else
                return 0;
        }
    }// while結束
}

int main()
{
    while (1) {
        int Request[m + 1];//當前的請求
        int p;//當前是幾號進程在請求資源;
        cout << "請輸入當前請求資源的進程編號(-1可退出): ";
        cin >> p;
        if (p > n) {
            cout << "輸入錯誤" << endl;
            continue;
        }
        if (p == -1)  return 0;//輸入-1 表示退出程序
        cout << "請輸入當前進程請求資源的向量: ";
        for (int i = 1; i <= m; i++)
            cin >> Request[i];

        int flag = 1;
        for (int i = 1; i <= m; i++) //檢查Request < Need 即請求是否合法(小於宣稱的最大值)
            if (Request[i] > Need[p][i])
                flag = 0;//不合法
        if (flag == 0) {
            cout << "不合法,因為請求資源大於宣稱的最大資源" << endl;
            continue;
        }
        for (int i = 1; i <= m; i++) //檢查Request[i] < Available[i] 即系統資源夠不夠當前用
            if (Request[i] > Available[i])
                flag = 0;//無法滿足
        if (flag == 0) {
            cout << "無法滿足,因為請求資源大於系統現有的資源數" << endl;
            continue;
        }
        //程序執行到此表示已經通過上述安全檢查,可以試探性的把資源分配給該進程:
        for (int i = 1; i <= m; i++) {
            Available[i] -= Request[i];
            Alloc[p][i] += Request[i];
            Need[p][i] -= Request[i];
        }
        //分配資源后,執行安全性算法檢查
        if (SafeCheck()) {
            cout << "安全檢查可以滿足,安全序列為:" << endl;
            StackPrint(Cstack);
        }
        else
            cout << "安全檢查無法滿足,該進程被阻塞:" << endl;

        for (int i = 1; i <= m; i++) {
            Available[i] += Request[i];
            Alloc[p][i] -= Request[i];
            Need[p][i] += Request[i];
        }
    }//主循環
}

運行結果:

根據題目要求,輸入四組測試數據進行測試,得到的結果如下圖:

在這里插入圖片描述

測試數據及結果整理到表格內可得:
編號 進程號 申請的資源 輸出結果:
1 2 0,3,4 無法滿足,因為請求資源大於系統現有的資源數
2 4 1,0,1 4 2 3 5 1
3 1 2,0,1 安全檢查無法滿足,該進程被阻塞:
4 3 0,0,2 3 2 4 5 1


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM