銀行家算法
針對多類資源分配的情況,最著名的而是銀行家算法,銀行家算法的設計思想是:當用戶申請一組資源時,系統必須做出判斷;如果把這些資源分出去,系統是否還處於安全狀態。若是,就可以分出這些資源;否則,該申請暫不予滿足。
實現銀行家算法要有若干數據結構,用來表示資源分配系統的狀態。
-
其中,n表示系統中進程的數目。M表示資源分類數。
-
Avaliable是一個長度爲m的向量,表示每一類資源可用的數量。Avaliable[j]=k,表示rj類資源可用的數量是k
-
Max是一個n*m矩陣,表示每個進程對資源的最大需求。Max[i,j]=k,表示進程pi至多課申請k個rj類資源單位
-
Allocation是一個n*m的矩陣,表示當前分給每個進程的資源數目,Allocation[i,j]=k,表示進程pi當前分到k個rj類資源
-
Need是一個n*m矩陣,他表示每個進程還缺少多少資源。Need[i,j]=k,表示進程pj尚需k個rj類資源才能完成其任務。顯然,Need[i,j]=Max[i,j]-Allocation[i,j]
-
Request 是一個n*m矩陣,i表示進程pi申請向量,Request[i][j]=k表示進程pi需要申請k個rj類資源
從文件讀取數據銀行家算法的驗證數據文件data格式說明
驗證數據:建立在程序目錄下建立data文件,文件內容是:
5 3
10 5 7
0 0 1 0 7 5 3
1 2 0 0 3 2 2
2 3 0 2 9 0 2
3 2 1 1 2 2 2
4 0 0 2 4 3 3
1 1 0 2
4 3 3 0
0 0 2 0
第一行:5個進程,3種資源。
第二行:每種資源系統擁有的最大數量。
3-7行:第一列是進程號(按順序排),2-4列是Request(資源請求)向量,5-7列是Max(最大資源需求量)向量。
8-10行:第一列是進程號,2-4列是Request(資源請求)向量。
運行程序,通過命令行參數指定文件,如: ./banker ./data運行。
代碼
/**
* lzy
*/
#include <stdio.h>
#include <unistd.h>
#define maxNum 100
#define maxLineNum 100
// 定義一個文件指針全局變量
FILE *fpl;
// 定義一個儲存文件一行的數組
char line[maxLineNum];
//定義一個數組用來儲存提取的字符
int lineData[maxLineNum];
// 定義一個數組來保存進程名,如processBox[1] = 2表示下標爲1時,對應的進程名爲2
int processBox[maxNum];
// 安全性算法需要用到的Work,Finish數組
int Work[maxNum];
int Finish[maxNum];
// 定義進程數目,定義資源分類數
int n, m;
int Resource[maxNum] = {0};
int Available[maxNum] = {0};
int Max[100][maxNum] = {0};
int Allocation[maxNum][maxNum] = {0};
int Need[maxNum][maxNum] = {0};
int Request[maxNum][maxNum] = {0};
char firstLetter;
/**
* 讀取line一行的數據到數組lineData中
* @param num 提取個數
*/
void updateLineData(int num) {
firstLetter = line[0];
int nape;
int cursor = 0;
for (int i = 0; i < num; ++i) {
nape = 0;
while ((int) line[cursor] != 32 && (int) line[cursor] != 0 && (int) line[cursor] != 10) {
nape = nape * 10 + (int) line[cursor] - 48;
++cursor;
}
++cursor;
lineData[i] = nape;
}
}
/**
* 初始化數據函數,
* @param src ,目標文件目錄
*/
void lzyInitData(char *src) {
// 1.初始化文件指針
fpl = fopen(src, "r");
if (fpl == NULL) {
printf("lzy:文件讀取失敗,沒有這個文件");
_exit(-1);
}
// 2.讀取文件,初始化各種全局變量
// 2.1初始化n、m
fgets(line, maxLineNum, fpl);
updateLineData(2);
n = lineData[0];
m = lineData[1];
// 2.2初始化Resource
fgets(line, maxLineNum, fpl);
updateLineData(m);
for (int i = 0; i < m; ++i) {
Resource[i] = lineData[i];
}
// 2.3初始化Allocation和Max,還有processBox
for (int j = 0; j < n; ++j) {
fgets(line, maxLineNum, fpl);
updateLineData(1 + 2 * m);
processBox[j] = lineData[0];
for (int i = 0; i < m; ++i) {
Allocation[lineData[0]][i] = lineData[i + 1];
Max[lineData[0]][i] = lineData[i + m + 1];
}
}
// 2.4初始化Available
for (int i = 0; i < m; ++i) {
int noAvailableNum = 0;
for (int k = 0; k < n; ++k) {
noAvailableNum += Allocation[processBox[k]][i];
}
Available[i] = Resource[i] - noAvailableNum;
}
// 2.4初始化Need
for (int k = 0; k < maxNum; ++k) {
for (int i = 0; i < maxNum; ++i) {
Need[k][i] = Max[k][i] - Allocation[k][i];
}
}
// 2.5初始化Request
fgets(line, maxLineNum, fpl);
updateLineData(1 + m);
if (firstLetter == '\n') {
fgets(line, maxLineNum, fpl);
updateLineData(1 + m);
}
while (1) {
for (int i = 0; i < m; ++i) {
Request[lineData[0]][i] = lineData[i + 1];
}
if (!fgets(line, maxLineNum, fpl)) {
break;
}
updateLineData(1 + m);
}
// 3.關閉文件流
fclose(fpl);
}
/**
* 檢測Request[process][i] 是否都小於Need[process][i],i=1,2,...,n
* @param process
* @return 結果 0:false 1:true
*/
int checkNeed(int process) {
for (int i = 0; i < m; ++i) {
if (Request[process][i] > Need[process][i]) return 0;
}
return 1;
}
/**
* 檢查Request i 和 Available的大小
* @param process
* @return
*/
int checkAvailable(int process) {
for (int i = 0; i < m; ++i) {
if (Request[process][i] > Available[i]) return 0;
}
return 1;
}
/**
* Available - Request[process][i]
* @param process
*/
void availableSubRequestI(int process) {
for (int i = 0; i < m; ++i) {
Available[i] -= Request[process][i];
}
}
/**
* Available = Available + Request[process][i]
* @param process
*/
void availableAddRequestI(int process) {
for (int i = 0; i < m; ++i) {
Available[i] += Request[process][i];
}
}
/**
* Allocation[process] = Allocation[process] + Request[process
* @param process
*/
void allocationAddRequest(int process) {
for (int i = 0; i < m; ++i) {
Allocation[process][i] += Request[process][i];
}
}
/**
* Allocation[process] = Allocation[process] - Request[process
* @param process
*/
void allocationSubRequest(int process) {
for (int i = 0; i < m; ++i) {
Allocation[process][i] -= Request[process][i];
}
}
/**
* Need[process] = Need[process] - Request[process]
* @param process
*/
void needSubRequest(int process) {
for (int i = 0; i < m; ++i) {
Need[process][i] -= Request[process][i];
}
}
/**
* Need[process] = Need[process] + Request[process]
* @param process
*/
void needAddRequest(int process) {
for (int i = 0; i < m; ++i) {
Need[process][i] += Request[process][i];
}
}
/**
* Work := Available
*/
void appendAvailableToWork() {
for (int i = 0; i < m; ++i) {
Work[i] = Available[i];
}
}
/**
* 重新初始化Finish
*/
void resetFinish() {
for (int i = 0; i < maxNum; ++i) {
Finish[i] = 0;
}
}
/**
* 判斷Need[process]中的每一項都小於等於Work[process]
* @param process
* @return
*/
int needSmallerOrEqualToWork(int process) {
for (int i = 0; i < m; ++i) {
if (Need[process][i] > Work[i]) {
return 0;
}
}
return 1;
}
/**
* 搜尋滿足下列條件的i值:Finish[i]=false,且NeedI =< Work
* @return 找不到,返回-1
*/
int searchIFinishEqualTo0AndNeedSmallerOrEqualToWork() {
for (int i = 0; i < n; ++i) {
if (Finish[processBox[i]] == 0 && needSmallerOrEqualToWork(processBox[i])) {
return i;
}
}
return -1;
}
/**
* Work:=Work+Allocation
* 回收資源
* @param process
*/
void workAddAllocation(int process) {
for (int i = 0; i < m; ++i) {
Work[i] += Allocation[process][i];
}
}
int FinishISAllTrue() {
for (int i = 0; i < n; ++i) {
if (!Finish[i]) {
return 0;
}
}
return 1;
}
int main(int argc, char *argv[]) {
if (argc == 1) {
printf("沒有輸入參數");
_exit(0);
}
// 初始化數據
lzyInitData(argv[1]);
int isSafe = 0;
for (int i = 0; i < n; ++i) {
int isAllZero = 1;
for (int j = 0; j < m; ++j) {
if (Request[i][j] != 0) {
isAllZero = 0;
break;
}
}
if (isAllZero) continue;
// 一、若Request i > Need i表示出錯,因爲進程對資源的申請量大於它說明的最大值
if (!checkNeed(processBox[i])) {
printf("lzy:錯誤!因爲進程對資源的申請量大於它說明的最大值");
_exit(-1);
}
// 二、若Request i > Available,則等待
if (!checkAvailable(processBox[i])) {
continue;
}
// 三、假設系統把申請的資源分給進程pi,則應對有關數據結構進行修改
availableSubRequestI(processBox[i]);
allocationAddRequest(processBox[i]);
needSubRequest(processBox[i]);
// 四、系統執行安全性算法,查看此時系統狀態是否安全,如果是安全的,就實際分配資源,
//滿足進程p1的此次申請;否則,若新狀態是不安全的,則pi等待,對所申請資源暫不予分配,
//並且把資源分配狀態恢復成三之前的情況
// 四-1 令Work和Finish分別表示長度爲m,n的向量,最初,置Work := Available,
// Finish[all]=false
appendAvailableToWork();
resetFinish();
// 四-2 搜尋滿足下列條件的i值:Finish[i]=false,且NeedI =< Work。若沒有找到,則轉向4.
int target = searchIFinishEqualTo0AndNeedSmallerOrEqualToWork();
while (target != -1) {
printf("進程%d的路徑可以爲:%d ->\n", processBox[i], processBox[target]);
// 四-3 修改數據值:Work:=Work+Allocation(p1釋放所佔資源),Finish[i]=true
workAddAllocation(processBox[target]);
Finish[processBox[target]] = 1;
target = searchIFinishEqualTo0AndNeedSmallerOrEqualToWork();
}
// 四-4 若Finish都爲true,則系統處於安全狀態,否則,系統處於不安全狀態,恢復三之前的情況
availableAddRequestI(processBox[i]);
allocationSubRequest(processBox[i]);
needAddRequest(processBox[i]);
if (!FinishISAllTrue()) {
printf("lzy:進程%d處於不安全狀態!\n", processBox[i]);
continue;
} else {
printf("lzy:處於安全狀態!");
printf("進程%d處於安全狀態滿足申請!\n\n", processBox[i]);
isSafe = 1;
}
}
if (!isSafe) {
printf("lzy:結果,無論怎麼樣,都處於不安全狀態!\n");
}
return 0;
}