银行家算法是Dijkstra给出的具有代表性的死锁避免算法。死锁是指多个进程因竞争系统资源或相互通信而处于永久阻塞状态,若无外力作用,则这些进程都将无法向前推进。为实现银行家算法,系统中必须设置若干数据结构。假定系统中有m个进程(p1,p2,···,Pm),n类资源(R1,R2,···,Rn),银行家算法中使用的数据结构如下:
(1)可利用资源向量Available
这是一个含有n个元素的数组,其中的每个元素代表一类资源的空闲资源数目,其初始值是系统中所配置的该类资源的数目,其数值随该类资源的分配和回收而动态地改变。如果Available(j)=k,则表示系统中现有空闲的Rj类资源k个。
(2)最大需求矩阵Max
这是一个m*n的矩阵,它定义了系统中每一个进程对各类资源的最大需求数目。如果Max(i,j)=k,则表示进程Pi需要Rj类资源的最大数目为k。
(3)分配矩阵Allocation
这是一个m*n的矩阵,它定义了系统中当前已分配给每一个进程的各类资源数目。
(4)需求矩阵Need
这是一个m*n的矩阵,它定义了系统中每一个进程还需要的各类资源数目。
上述三个矩阵间存在关系:Need(i,j)=Max(i,j)-Allocation(i,j)
银行家算法的实现思想如下:
银行家算法的基本思想是分配资源之前, 判断系统是否是安全的; 若是, 才分配。它是最具有代表性的避免死锁的算法。
设进程cusneed 提出请求REQUEST [i] ,则银行家算法按如下规则进行判断。
(1) 如果REQUEST [cusneed] [i]<= NEED[cusneed][i] ,则转(2) ;否则,出错。
(2) 如果REQUEST [cusneed] [i]<= AVAILABLE[cusneed][i] ,则转(3) ;否则,出错。
(3) 系统试探分配资源,修改相关数据:
AVAILABLE[i]-=REQUEST[cusneed][i];
ALLOCATION[cusneed][i]+=REQUEST[cusneed][i];
NEED[cusneed][i]-=REQUEST[cusneed][i];
(4) 系统执行安全性检查,如安全,则分配成立;否则试探险性分配作废,系统恢复原状,进程等待。
三、安全性检查算法
(1) 设置两个工作向量Work=AVAILABLE;FINISH
(2) 从进程集合中找到一个满足下述条件的进 程,
FINISH==false;
NEED<=Work;
如找到,执行(3) ; 否则,执行(4)
(3) 设进程获得资源,可顺利执行,直至完成,从而释放资源。
Work+=ALLOCATION;
Finish=true;
GOTO 2
(4) 如所有的进程Finish= true ,则表 示安全;否则系统不安全。
操作系统安全状态和不安全状态:
安全序列是指一个进程序列{P1,…,Pn}是安全的,如果对于每一个进程Pi(1≤i≤n),它以后尚需要的资源量不超过系统当前剩余资源量与所有进程Pj (j < i )当前占有资源
量之和。
如果存在一个由系统中所有进程构成的安全序列P1,…,Pn,则系统处于安全状态。安全状态一定是没有死锁发生。
不存在一个安全序列。不安全状态不一定导致死锁。
代码如下:
// BankAlgorithm.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdio.h"
#define MAXPROCESS 4 /*最大进程数*/
#define MAXRESOURCE 3 /*最大资源数*/
int AVAILABLE[MAXRESOURCE] = {1,1,2}; /*可用资源数组*/
int MAX[MAXPROCESS][MAXRESOURCE] = { {3,2,2},{6,1,3},{3,1,4},{4,2,2} }; /*最大需求矩阵*/
int ALLOCATION[MAXPROCESS][MAXRESOURCE] = { {1,0,0},{5,1,1},{2,1,1},{0,0,2} }; /*分配矩阵*/
int NEED[MAXPROCESS][MAXRESOURCE]; /*需求矩阵*/
int REQUEST[MAXPROCESS][MAXRESOURCE]; /*进程需要资源数*/
bool FINISH[MAXPROCESS]; /*系统是否有足够的资源分配*/
int WORK[MAXRESOURCE]; /*记录序列*/
int m, n; /*m个进程,n个资源*/
void init();
void bank();
bool safe();
void printData();
int main()
{
init();
bank();
<span style="white-space:pre"> </span>return 0;
}
void init() { //初始化算法
m = 4;
n = 3;
/*int i, j;
printf("请输入进程数和资源种类:");
scanf_s("%d%d", &m, &n);
printf("请输入每个进程所需要的最多资源数:(逐个按照进程分配)");
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
scanf_s("%d", &MAX[i][j]);
}
}*/
/*for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
ALLOCATION[i][j] = 0;
NEED[i][j] = MAX[i][j] - ALLOCATION[i][j];
}
}*/
/*printf("请输入系统中当前已分配给每一个进程的各类资源数目:\n");
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
scanf_s("%d", &ALLOCATION[i][j]);
NEED[i][j] = MAX[i][j] - ALLOCATION[i][j];
if (NEED[i][j] < 0) {
printf("输入有误,请重新输入该数:");
j--;
continue;
}
}
}*/
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
NEED[i][j] = MAX[i][j] - ALLOCATION[i][j];
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
printf("%d", NEED[i][j]);
}
}
}
void bank() {
int id, i;
char isCon;
while (true) {
input:
printf("请输入要申请资源的进程号(从0开始):");
scanf_s("%d", &id);
if (id > (m - 1)) {
printf("该进程不存在,请重新输入");
goto input;
}
printf("请输入该进程请求的各类资源:");
for (i = 0; i < n; i++) {
scanf_s("%d", &REQUEST[id][i]);
}
//判断该进程需要的资源是否大于原先定义的数量
for (i = 0; i < n; i++) {
if (REQUEST[id][i]>NEED[id][i]) {
printf("无法分配,请重新分配资源\n");
goto input;
}
}
//判断系统中是否有足够的资源
for (i = 0; i < n; i++) {
if (REQUEST[id][i]>AVAILABLE[i]) {
printf("系统中尚无足够的资源填满%d进程的请求\n", id);
goto input;
}
}
//系统试着把资源分配给该进程
for (i = 0; i < n; i++) {
AVAILABLE[i] = AVAILABLE[i] - REQUEST[id][i];
ALLOCATION[id][i] = ALLOCATION[id][i] + REQUEST[id][i];
NEED[id][i] = NEED[id][i] - REQUEST[id][i];
}
if (safe()) {
printf("分配成功!\n");
printData();
printf("是否继续?继续请输入y,退出请任意字符\n");
getchar();
scanf_s("%c", &isCon);
if (isCon == 'y' || isCon == 'Y') {
goto input;
}
else {
break;
}
}
else {
for (i = 0; i < n; i++) {
NEED[id][i] = NEED[id][i] + REQUEST[id][i];
ALLOCATION[id][i] = ALLOCATION[id][i] - REQUEST[id][i];
AVAILABLE[i] = AVAILABLE[i] + REQUEST[id][i];
}
printf("分配失败");
printf("是否继续?继续请输入y,退出请任意字符\n");
char isCon1;
getchar();
scanf_s("%c", &isCon1);
if (isCon1 == 'y' || isCon1 == 'Y') {
goto input;
}
else {
break;
}
}
}
}
bool safe() {
int i, j, flag = 0;
bool isJump = true;
step1:
for (i = 0; i < n; i++) {
WORK[i] = AVAILABLE[i];
}
for (i = 0; i < n; i++) {
printf("%d",WORK[i]);
}
for (i = 0; i < m; i++)
FINISH[i] = false;
step2:
isJump = true;
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
/*if (NEED[i][j]<=WORK[j]) {
goto step4;
}*/
if (FINISH[i] == true) {
isJump = false;
break;
}
else {
if (NEED[i][j] <= WORK[j]) {
isJump = true;
continue;
}
else {
isJump = false;
break;
}
}
/*if (FINISH[i] == false) {
goto step3;
flag = i;
}*/
}
if (isJump == true) {
flag = i;
goto step3;
}
//isJump = true;
}
goto step4;
step3:
for (i = 0; i < n; i++) {
WORK[i] = WORK[i] + ALLOCATION[flag][i];
}
FINISH[flag] = true;
goto step2;
step4:
for (i = 0; i < m; i++) {
if (FINISH[i] == false) {
return false;
}
}
return true;
}
void printData() {
int i, j;
printf("各进程还需要的资源量为:\n");
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
printf("%d ", NEED[i][j]);
}
printf("\n");
}
printf("系统可用的资源数为:\n");
for (i = 0; i < n; i++) {
printf("%d ", AVAILABLE[i]);
}
printf("\n");
printf("各进程已得到的资源量:\n");
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
printf("%d ", ALLOCATION[i][j]);
}
printf("\n");
}
}
上面的代码中,因为我用的是VS2015,scanf这个函数因为不安全无法使用,用的是scanf_s。安全性算法,就我理解就是假设在为当前请求进程分配资源后保证至少有一个进程可以获得需要的最大资源,这样就可以保证该系统始终存在进程可获得最大资源,满足该条件即可为当前请求的进程分配资源。
银行家算法是我很早之前写的,有些地方注释不是很完整,有问题的欢迎讨论。