目錄
一、實驗目的
通過編寫一個模擬動態資源分配的銀行家算法程序,進一步深入理解死鎖、產生死鎖的必要條件、安全狀態等重要概念,並掌握避免死鎖的具體實施方法。
二、實驗內容
- (1)模擬一個銀行家算法: 設置數據結構 設計安全性算法
- (2) 初始化時讓系統擁有一定的資源
- (3) 用鍵盤輸入的方式申請資源
- (4)如果預分配後,系統處於安全狀態,則修改系統的資源分配情況
- (5)如果預分配後,系統處於不安全狀態,則提示不能滿足請求
三、實驗要點說明
數據結構
- 可利用資源向量 int Available[m] m爲資源種類
- 最大需求矩陣 int Max[n][m] n爲進程的數量
- 分配矩陣 int Allocation[n][m]
- 還需資源矩陣 int need[i][j]=Max[i][j]- Allocation[i][j]
- 申請資源數量 int Request [m]
- 工作向量 int Work[m] int Finish[n]
銀行家算法bank()函數
Requesti:進程Pi的請求向量。 0<=j<=m-1
- (1) 若 Requesti[j] ≤ Need[i,j],轉向(2),否則出錯。
- (2) 若 Requesti[j] ≤ Available[j],轉向(3),否則等待。
- (3) 系統試探着把資源分配給進程Pi,修改下面內容:
- Available[j] = Available[j] – Requesti[j];
- Allocation[i,j] = Allocation[i,j] + Requesti[j];
- Need[i,j] = Need[i,j] –Requesti[j];
- (4) 試分配後,執行安全性算法,檢查此次分配後系統是否處於安全狀態。若安全,才正式分配;否則,此次試探性分配作廢,進程Pi等待。
安全性算法safe()函數
- (1) 初始化:設置兩個向量Work(1×m)和Finish(1×n)
- Work – 系統可提供給進程繼續運行所需各類資源數,初態賦值Available
- Finish – 系統是否有足夠資源分配給進程,初值false.
- (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 (2).
- (4) 若所有進程Finish[i] = true,表示系統處於安全狀態,否則處於不安全狀態。
先對用戶提出的請求進行合法性檢查,即檢查請求的是否不大於需要的,是否不大於可利用的。 若請求合法,則進行試分配。最後對試分配後的狀態調用安全性檢查算法進行安全性檢查。 若安全,則分配,否則,不分配,恢復原來狀態,拒絕申請。
銀行家算法實例
假定系統中有五個進程{P0、P1、P2、P3、P4}和三種類型資源{A、B、C},每一種資源的數量分別爲10、5、7。各進程的最大需求、T0時刻資源分配情況如下所示。
試問:
- ①T0時刻是否安全?
- ② T0之後的T1時刻P1請求資源Request1(1,0,2)是否允許?
- ③ T1之後的T2時刻P4請求資源Request4(3,3,0)是否允許?
- ④ T2之後的T3時刻P0請求資源Request0(0,2,0)是否允許?
解:
① T0時刻是否安全? 工作向量Work.它表示系統可提供給進程繼續運行所需要的各類資源的數目
(1) T0時刻安全性分析
存在安全序列{P1, P3, P4, P0, P2},系統安全。
(2) T0之後的T1時刻P1請求資源Request1(1,0,2)可否允許?
- ①Request1(1,0,2) ≤ Need1(1,2,2),P1請求在最大需求範圍內
- ②Request1(1,0,2) ≤ Available1(3,3,2),可用資源可滿足P1請求需要
- ③假定可爲P1分配,修改Available,Allocation1,Need1向量
- Available(2,3,0) = Available(3,3,2)-Request1(1,0,2);
- Need1(0,2,0) = Need1(1,2,2)-Request1(1,0,2);
- Allocation1(3,0,2) =Allocation1(2,0,0)+Request1(1,0,2);
- ④利用安全性算法檢查試探將資源分配後狀態的安全性
存在安全序列{P1, P3, P4, P0, P2},所以試探將資源分配給進程P1後的狀態是安全的,可將資源分配給進程P1。
③ T1之後的T2時刻P4請求資源Request4(3,3,0)是否允許?
- Request4(3,3,0)≤Need4(4,3,1),P4請求在最大需求範圍內。
- Request4(3,3,0)≤Available(2,3,0)不成立,即可用資源暫不能滿足P4請求資源需要,P4阻塞等待。
P4請求資源Request4(3,3,0)不允許。
④ T2之後的T3時刻P0請求資源Request0(0,2,0)是否允許?
- Request0(0,2,0)≤Need0(7,4,3);
- Request0(0,2,0)≤Available(2,3,0);
系統暫時先假定可爲P0分配資源,並修改有關數據,如下圖所示:
進行安全性檢查:可用資源Available(2,1,0)已不能滿足任何進程的需要,故系統進入不安全狀態,此時系統不分配資源。
程序結構
程序共有以下五個部分:
- (1).初始化init():輸入進程數量、資源種類、資源可利用量、進程資源已分配量、進程最大需求量
- (2).當前安全性檢查safe():用於判斷當前狀態安全
- (3).銀行家算法bank():進行銀行家算法模擬實現的模塊
- (4).顯示當前狀態show():顯示當前資源分配詳細情況
- (5).主程序main():逐個調用初始化、顯示狀態、安全性檢查、銀行家算法函數,使程序有序的進行
四、實驗代碼
#include<stdio.h>
#include<stdlib.h>
#define False 0
#define True 1
/********主要數據結構********/
char NAME[100]={0};//資源的名稱
int Max[100][100]={0};//最大需求矩陣
int Allocation[100][100]={0};//系統已分配矩陣
int Need[100][100]={0};//還需要資源矩陣
int Available[100]={0};//可用資源矩陣
int Request[100]={0};//請求資源向量
int Work[100]={0};//存放系統可提供資源量
int Finish[100]={0}; //標記系統是否有足夠的資源分配給各個進程
int Security[100]={0};//存放安全序列
int M=100;//進程的最大數
int N=100;//資源的最大數
/********初始化數據:輸入進程數量、資源種類、各種資源可利用數量、
各進程對資源最大需求量、各進程的資源已分配數量等。********/
void init()
{
/* m爲進程個數,即矩陣行數,n爲資源種類,即矩陣列數。*/
int i,j,m,n;
int number,flag;
char name;//輸入資源名稱
int temp[100]={0};//統計已經分配的資源
//輸入系統資源數目及各資源初試個數
printf("系統可用資源種類爲:");
scanf("%d",&n);
N=n;
for(i=0;i<n;i++)
{
printf("資源%d的名稱:",i);
fflush(stdin); //清空輸入流緩衝區的字符,注意必須引入#include<stdlib.h>頭文件
scanf("%c",&name);
NAME[i]=name;
printf("資源%c的初始個數爲:",name);
scanf("%d",&number);
Available[i]=number;
}
//輸入進程數及各進程的最大需求矩陣
printf("\n請輸入進程的數量:");
scanf("%d",&m);
M=m;
printf("請輸入各進程的最大需求矩陣的值[Max]:\n");
do{
flag = False;
for(i=0;i<M;i++)
for(j=0;j<N;j++)
{
scanf("%d",&Max[i][j]);
if(Max[i][j]>Available[j])
flag = True;
}
if(flag)
printf("資源最大需求量大於系統中資源最大量,請重新輸入!\n");
} while(flag);
//輸入各進程已經分配的資源量,並求得還需要的資源量
do{
flag=False;
printf("請輸入各進程已經分配的資源量[Allocation]:\n");
for(i=0;i<M;i++)
{
for(j=0;j<N;j++)
{
scanf("%d",&Allocation[i][j]);
if(Allocation[i][j]>Max[i][j])
flag=True;
Need[i][j]=Max[i][j]-Allocation[i][j];
temp[j]+=Allocation[i][j];//統計已經分配給進程的資源數目
}
}
if(flag)
printf("分配的資源大於最大量,請重新輸入!\n");
}while(flag);
//求得系統中可利用的資源量
for(j=0;j<N;j++)
Available[j]=Available[j]-temp[j];
}
/********顯示資源分配矩陣********/
void showdata()
{
int i,j;
printf("*************************************************************\n");
printf("系統目前可用的資源[Available]:\n");
for(i=0;i<N;i++)
printf("%c ",NAME[i]);
printf("\n");
for(j=0;j<N;j++)
printf("%d ",Available[j]);
printf("\n");
printf("系統當前的資源分配情況如下:\n");
printf(" Max Allocation Need\n");
printf("進程名 ");
//輸出與進程名同行的資源名,Max、Allocation、Need下分別對應
for(j=0;j<3;j++){
for(i=0;i<N;i++)
printf("%c ",NAME[i]);
printf(" ");
}
printf("\n");
//輸出每個進程的Max、Allocation、Need
for(i=0;i<M;i++){
printf(" P%d ",i);
for(j=0;j<N;j++)
printf("%d ",Max[i][j]);
printf(" ");
for(j=0;j<N;j++)
printf("%d ",Allocation[i][j]);
printf(" ");
for(j=0;j<N;j++)
printf("%d ",Need[i][j]);
printf("\n");
}
}
/********嘗試分配資源********/
int test(int i) //試探性的將資源分配給第i個進程
{
for(int j=0;j<N;j++)
{
Available[j]=Available[j]-Request[j];
Allocation[i][j]=Allocation[i][j]+Request[j];
Need[i][j]=Need[i][j]-Request[j];
}
return True;
}
/********試探性分配資源作廢********/
int Retest(int i) //與test操作相反
{
for(int j=0; j<N; j++)
{
Available[j] = Available[j] + Request[j];
Allocation[i][j] = Allocation[i][j] - Request[j];
Need[i][j] = Need[i][j] + Request[j];
}
return True;
}
/********安全性算法********/
int safe()
{
int i,j,k=0,m,apply;
//初始化work
for(j=0;j<N;j++)
Work[j] = Available[j];
//初始化Finish
for(i=0;i<M;i++)
Finish[i] = False;
//求安全序列
for(i=0;i<M;i++){
apply=0;
for(j=0;j<N;j++){
if(Finish[i]==False && Need[i][j]<=Work[j])
{
apply++;
//直到每類資源尚需數都小於系統可利用資源數纔可分配
if(apply==N)
{
for(m=0;m<N;m++)
Work[m]=Work[m]+Allocation[i][m];//更改當前可分配資源
Finish[i]=True;
Security[k++]=i;
i=-1; //保證每次查詢均從第一個進程開始
}
}
}
}
for(i=0;i<M;i++){
if(Finish[i]==False){
printf("系統不安全\n");//不成功系統不安全
return False;
}
}
printf("系統是安全的!\n");//如果安全,輸出成功
printf("存在一個安全序列:");
for(i=0;i<M;i++){//輸出運行進程數組
printf("P%d",Security[i]);
if(i<M-1)
printf("->");
}
printf("\n");
return True;
}
/********利用銀行家算法對申請資源進行試分********/
void bank()
{
int flag = True;//標誌變量,判斷能否進入銀行家算法的下一步
int i,j;
printf("請輸入請求分配資源的進程號(0-%d):",M-1);
scanf("%d",&i);//輸入須申請資源的進程號
printf("請輸入進程P%d要申請的資源個數:\n",i);
for(j=0;j<N;j++)
{
printf("%c:",NAME[j]);
scanf("%d",&Request[j]);//輸入需要申請的資源
}
//判斷銀行家算法的前兩條件是否成立
for (j=0;j<N;j++)
{
if(Request[j]>Need[i][j])//判斷申請是否大於需求,若大於則出錯
{
printf("進程P%d申請的資源大於它需要的資源",i);
printf("分配不合理,不予分配!\n");
flag = False;
break;
}
else
{
if(Request[j]>Available[j])//判斷申請是否大於當前可分配資源,若大於則出錯
{
printf("進程%d申請的資源大於系統現在可利用的資源",i);
printf("\n");
printf("系統尚無足夠資源,不予分配!\n");
flag = False;
break;
}
}
}
//前兩個條件成立,試分配資源,尋找安全序列
if(flag) {
test(i); //根據進程需求量,試分配資源
showdata(); //根據進程需求量,顯示試分配後的資源量
if(!safe()) //尋找安全序列
{
Retest(i);
showdata();
}
}
}
int main()//主函數
{
char choice;
printf("\t---------------------------------------------------\n");
printf("\t|| ||\n");
printf("\t|| 銀行家算法的實現 ||\n");
printf("\t|| ||\n");
printf("\t|| ||\n");
printf("\t|| 在此輸入個人姓名:****** ||\n");
printf("\t|| ||\n");
printf("\t---------------------------------------------------\n");
init();//初始化數據
showdata();//顯示各種資源
//用銀行家算法判定系統當前時刻是否安全,不安全就不再繼續分配資源
if(!safe()) exit(0);
do{
printf("*************************************************************\n");
printf("\n");
printf("\n");
printf("\t-------------------銀行家算法演示------------------\n");
printf(" R(r):請求分配 \n");
printf(" E(e):退出 \n");
printf("\t---------------------------------------------------\n");
printf("請選擇:");
fflush(stdin); //清空輸入流緩衝區的字符,注意必須引入#include<stdlib.h>頭文件
scanf("%c",&choice);
switch(choice)
{
case 'r':
case 'R':
bank();break;
case 'e':
case 'E':
exit(0);
default: printf("請正確選擇!\n");break;
}
} while(choice);
}
五、實驗運行結果