1 需求分析
1.1 銀行家算法的實現思想
允許進程動態地申請資源,系統在每次實施資源分配之前,先計算資源分配的安全性,若此次資源分配安全(即資源分配后,系統能按某種順序來為每個進程分配其所需的資源,直至最大需求,使每個進程都可以順利地完成),便將資源分配給進程,否則不分配資源,讓進程等待。
1.2 死鎖的概念
死鎖是指兩個或兩個以上的進程在執行過程中,由於競爭資源或者由於彼此通信而造成的一種阻塞的現象,若無外力作用,它們都將無法推進下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱為死鎖進程。
銀行家算法是避免死鎖的一種重要方法。 操作系統按照銀行家制定的規則為進程分配資源,當進程首次申請資源時,要測試該進程對資源的最大需求量,如果系統現存的資源可以滿足它的最大需求量則按當前的申請量分配資源,否則就推遲分配。當進程在執行中繼續申請資源時,先測試該進程已占用的資源數與本次申請的資源數之和是否超過了該進程對資源的最大需求量。若超過則拒絕分配資源,若沒有超過則再測試系統現存的資源能否滿足該進程尚需的最大資源量,若能滿足則按當前的申請量分配資源,否則也要推遲分配。
1.3 產生死鎖的必要條件
① 互斥條件:指進程對所分配到的資源進行排它性使用,即在一段時間內某資源只由一個進程占用。如果此時還有其它進程請求資源,則請求者只能等待,直至占有資源的進程用畢釋放。
② 請求和保持條件:指進程已經保持至少一個資源,但又提出了新的資源請求,而該資源已被其它進程占有,此時請求進程阻塞,但又對自己已獲得的其它資源保持不放。
③ 不剝奪條件:指進程已獲得的資源,在未使用完之前,不能被剝奪,只能在使用完時由自己釋放。
④ 環路等待條件:指在發生死鎖時,必然存在一個進程——資源的環形鏈,即進程集合{P0,P1,P2,···,Pn}中的P0正在等待一個P1占用的資源;P1正在等待P2占用的資源,……,Pn正在等待已被P0占用的資源。
1.4功能實現
理解了死鎖的原因,尤其是產生死鎖的四個必要條件,就可以最大可能地避免、預防和解除死鎖。所以,在系統設計、進程調度等方面注意如何能夠不讓這四個必要條件成立,如何確定資源的合理分配算法,避免進程永久占據系統資源。此外,也要防止進程在處於等待狀態的情況下占用資源,在系統運行過程中,對進程發出的每一個系統能夠滿足的資源申請進行動態檢查,並根據檢查結果決定是否分配資源,若分配后系統可能發生死鎖,則不予分配,否則予以分配 。因此,對資源的分配要給予合理的規划。
2 概要設計
2.1數據結構
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]
2.2 設計思路
第一部分:銀行家算法模塊
1.如果Request<=Need,則轉向2;否則,出錯
2.如果Request<=Available,則轉向3,否則等待
3.系統試探分配請求的資源給進程
4.系統執行安全性算法
第二部分:安全性算法模塊
1. 設置兩個向量
① 工作向量:Work=Available(表示系統可提供給進程繼續運行所需要的各類資源數目)
② Finish:表示系統是否有足夠資源分配給進程(True:有;False:沒有).初始化為False
2. 若Finish[i]=False&&Need<=Work,則執行3;否則執行4(i為資源類別)
3. 進程P獲得第i類資源,則順利執行直至完成,並釋放資源: Work=Work+Allocation; Finish[i]=true;轉2
4. 若所有進程的Finish[i]=true,則表示系統安全;否則,不安全!
3 詳細設計
在系統運行過程中,對進程發出的每一個系統能夠滿足的資源申請進行動態檢查,並根據檢查結果決定是否分配資源,若分配后系統可能發生死鎖,則不予分配,否則予以分配 。因此,對資源的分配要給予合理的規划。
3.1銀行家算法
設Request i是進程Pi的申請向量,如果Request i[j]=K,則表示進程Pi需要K個Rj類型的資源。當Pi發出資源請求后,系統按下述步驟進行檢查:
1) 如果Request i[j]<=Need[i,j],便轉向步驟2);否則認為出錯,因為它所需要的資源數已經超過它所宣布的最大值。
2) 如果Request i[j]<=Available[i,j],便轉向步驟3);否則,表示尚無足夠資源,Pi需等待。
3) 系統試探着把資源分配給進程Pi,並修改下面數據結構中的數值:
Available[j]:=Available[j]-Request i[j];
Allocation[i,j]:=Allocation[i,j]+Request i[j];
Need[i,j]:=Need[i,j]-Request i[j];
4) 系統執行安全性算法,檢查此次資源分配后系統是否處於安全狀態。若安全,才正式將資源分配給進程Pi,以完成本次分配;否則,將本次的試探分配作廢,恢復原來的資源分配狀態,讓進程Pi等待。
3.2安全性算法
系統所執行的安全性算法可描述如下:
1) 設置兩個向量
① 工作向量Work,它表示系統可提供給進程繼續運行所需的各類資源數目,它含有m個元素,在執行安全算法開始時,Work:=Available。
② Finish,它表示系統是否有足夠的資源分配給進程,使之運行完成。開始時先做Finish[i]:=false;當有足夠資源分配給進程時,再令Finish[i]:=ture.
2) 從進程集合中找到一個滿足下述條件的進程:
① Finish[i]=false;
② Need[i,j]<=Work[j];若找不到,執行步驟3),否則,執行步驟4)。
3) 當進程Pi獲得資源后,可順利執行,直至完成,並釋放出分配給它的資源,故應執行:
Work[j]:=Work[j]+Allocation[i,j];
Finish[i]:=true;
Go to step 2;
4) 如果所有進程的Finish[i]=true都滿足,則表示系統處於安全狀態;否則,系統處於不安全狀態。
3.3流程圖
4 測試
4.1結果截圖
首先進行初始化:
T0時刻進行安全性檢測,得到安全序列2->4->5->1->3
T0時刻的資源情況分配圖:
P2請求資源,並得到安全序列2->4->5->1->3
P5請求資源:
P1請求資源:
P2請求資源
4.2結果分析
1. T0時刻,利用安全性算法對T0時刻的資源分配情況進行分析,可知,在T0時刻存在着一個安全序列{P[2],P[4],P[5],P[1],P[3]},故系統是安全的。
2. P2請求資源:P2發出請求向量Request2(1,0,2),系統按銀行家算法進行檢查:
① Request 2(1,0,2)<=Need 2(1,2,2,)
② Request 2(1,0,2)<=Available 2(3,3,2)
系統先假定可為P2分配資源,並修改Available,Allocation2和Need2向量,再利用安全性算法檢查此時系統是否安全;找到一個安全序列{P[2],P[4],P[5],P[1],P[3]},因此,系統是安全的,可立即將P2所申請的資源分配給它。
3. P5請求資源:P5發出請求向量Request5(3,3,0),系統按照銀行家算法進行檢查:
① Request 5(3,3,0)<=Need 5(4,3,1)
② Request 5(3,3,0)<=Available 5(2,3,0),讓P5等待
4. P1請求資源:P1發出請求向量Request1(0,2,0),系統按照銀行家算法進行檢查:
① Request 1(0,2,0)<=Need 2(7,4,3)
② Request 1(0,2,0)<=Available 2(2,3,0)
系統先假定可為P0分配資源,並修改數據,進行安全性檢查:
可用資源Available(2,1,0)已不能滿足任何進程需求,故系統進入不安全狀態,此時系統不分配資源。
5. P2請求資源:P2發出請求向量Request2(0,2,0),系統按銀行家算法進行檢查,可以檢測到安全序列。此時進程P2執行完畢,回收P2的已分配資源。
//附錄:源代碼 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> int Available[10]; //可使用資源向量 int Max[10][10]; //最大需求矩陣 int Allocation[10][10] = { 0 }; //分配矩陣 int Need[10][10] = { 0 }; //需求矩陣 int Work[10]; //工作向量 int Finish[10]; //是否有足夠的資源分配,狀態標志 int Request[10][10]; //進程申請資源向量 int Pause[10]; int arr[] = { 0 }; //各類資源總數 int List[10]; int i, j; int n; //系統資源總數 int m; //總的進程數 int a; //當前申請的進程號 int l, e; //計數器 int b = 0, c = 0, f = 0, g; //計數器 int z = 0; int securitycheck() //安全性檢測 { printf("\n\n"); printf("\t\t\t※ 安全性檢測 ※\n\n"); if (n == 3) { printf(" 工作向量 尚需求量 已分配 工作向量+已分配\n進程 "); for (c = 1; c <= 4; c++) { for (j = 1; j <= n; j++) { printf(" %d類", j); } } } if (n == 2) { printf(" 工作向量 尚需求量 已分配 工作向量+已分配\n進程 "); for (c = 1; c <= 4; c++) { for (j = 1; j <= n; j++) { printf(" %d類", j); } } } for (i = 1; i <= m; i++) { Pause[i] = Available[i]; //Pause[i]只是一個暫時寄存的中間變量,為防止在下面安全性檢查時修改到Available[i]而代替的一維數組 Finish[i] = false; } for (g = 1; g <= m; g++) { for (i = 1; i <= m; i++) { b = 0; //計數器初始化 Finish[i] == false; for (j = 1; j <= n; j++) { if (Need[i][j] <= Pause[j]) { b = b + 1; } if (Finish[i] == false && b == n) { Finish[i] = true; printf("\nP[%d] ", i); //依次輸出進程安全序列 for (l = 1; l <= n; l++) { printf(" %2d ", Pause[l]); } for (j = 1; j <= n; j++) { printf(" %2d ", Need[i][j]); } for (j = 1; j <= n; j++) { //Allocation[i][j]=Pause[j]-Need[i][j]; printf(" %2d ", Allocation[i][j]); } for (j = 1; j <= n; j++) { printf(" %2d ", Pause[j] + Allocation[i][j]); } for (l = 1; l <= n; l++) { Pause[l] = Pause[l] + Allocation[i][l]; } } } } } printf("\n\n"); for (i = 1; i <= m; i++) { if (Finish[i] == true) f = f + 1; //統計Finish[i]==true的個數 } if (f == m) { printf("safe state"); printf("\n\n系統剩余資源量: "); for (i = 1; i <= n; i++) { printf(" %d ", Available[i]); } f = 0; //將計數器f重新初始化,為下一次提出新的進程申請做准備 return 1; } else { printf("unsafe state "); for (i = 1; i <= n; i++) { Available[i] = Available[i] + Request[a][i]; Allocation[a][i] = Allocation[a][i] - Request[a][i]; Need[a][i] = Need[a][i] + Request[a][i]; } return 0; } } void initialize() //初始化 { printf("請輸入系統的資源種類數:"); scanf("%d", &n); for (i = 1; i <= n; i++) { printf("第%d類資源總數:", i); scanf("%d", &arr[i]); } printf("請輸入進程總數:"); scanf("%d", &m); for (i = 1; i <= m; i++) { for (j = 1; j <= n; j++) { printf("進程P[%d]對第%d類資源的最大需求量:", i, j); scanf("%d", &Max[i][j]); } } for (i = 1; i <= m; i++) { for (j = 1; j <= n; j++) { printf("進程P[%d]對第%d類資源已分配數:", i, j); scanf("%d", &Allocation[i][j]); Need[i][j] = Max[i][j] - Allocation[i][j]; } } for (i = 1; i <= n; i++) { for (j = 1; j <= m; j++) { arr[i] -= Allocation[j][i]; } } for (i = 1; i <= n; i++) Available[i] = arr[i]; securitycheck(); } void mainrequest() //進程申請資源 { printf("請輸入申請資源的進程:"); scanf("%d", &a); for (i = 1; i <= n; i++) { printf("請輸入進程P[%d]對%d類資源的申請量:", a, i); scanf("%d", &Request[a][i]); if (Request[a][i] > Need[a][i]) { printf("\n出錯!進程申請的資源數多於它自己申報的最大需求量\n"); return; } if (Request[a][i] > Available[i]) { printf("\nP[%d]請求的資源數大於可用資源數,必須等待\n", a); return; } } for (i = 1; i <= n; i++) { //以下是試探性分配 Available[i] = Available[i] - Request[a][i]; Allocation[a][i] = Allocation[a][i] + Request[a][i]; Need[a][i] = Need[a][i] - Request[a][i]; } int ret=securitycheck(); if (ret == 1) { int key = 0; for (j = 1; j <= n; j++) { if (Need[a][j] == 0) { key++; } } if (key == n) { for (j = 1; j <= n; j++) { Available[j] += Allocation[a][j]; Allocation[a][j] = 0; } } } } void mainshow() { printf("\n\n"); if (n == 3) { printf(" 已分配 最大需求量 尚需要量 \n進程"); } if (n == 2) { printf(" 已分配 最大需求 尚需要量 \n進程"); } for (i = 1; i <= 3; i++) { for (j = 1; j <= n; j++) { printf(" %d類", j); } } for (i = 1; i <= m; i++) { printf("\nP[%d]", i); for (j = 1; j <= n; j++) { printf(" %2d ", Allocation[i][j]); } for (j = 1; j <= n; j++) { printf(" %2d ", Max[i][j]); } for (j = 1; j <= n; j++) { printf(" %2d ", Need[i][j]); } } printf("\n\n系統剩余資源量: "); for (i = 1; i <= n; i++) { printf(" %d ", Available[i]); } printf("\n"); } void menu() { printf("\n\n\t\t卐卍※§ 銀行家算法 §※卐卍\n"); printf("\n\n\t\t\t1:初始化"); printf("\n \t\t\t2:進程進行資源申請"); printf("\n \t\t\t3:資源分配狀態"); printf("\n \t\t\t4:退出程序"); printf("\n\n\t\t\t\t\t 請輸入你的選擇: "); } int main() { int key = 0; printf("\n\n"); while (1) { menu(); scanf("%d", &key); printf("\n\n"); switch (key) { case 1: initialize(); break; case 2: mainrequest(); break; case 3: mainshow(); break; case 4: printf("\n\n\t\t\t謝謝使用 \n"); printf("\n\t\t\tSee you next time !\n\n\n"); system("pause"); return 0; } } system("pause"); return 0; }