算法思路
将操作系统看作是银行家,操作系统所拥有的资源就相当于银行家所拥有的资产,进程向操作系统申请资源就相当于资产家向银行贷款,规定资产家在向银行贷款之前,先申明其所贷数额的最大值,申明之后其贷款的数额不得超过此最大值,而银行家应该合理安排贷款给各个资产家的顺序,以保证银行不会破产;显然将钱全部分配给一位资本家是十分不合理的这样银行家将承担很大的风险;
算法所用到的数据结构
- max[ ][ ]:用于记录进程对系统中各个资源的最大需求量,如max[i][j]表示第i个进程对系统中的Rj资源的最大需求量
- allocation[ ][ ]:表示各个进程已经分配到的资源的数目,比如allocation[i][j]表示第i个进程目前分配到资源Rj的数目
- available[ ]:表示目前系统中各个资源可用的数量,比如available[i]表示资源Ri此时的可用数量
- need[ ][ ]:表示进程此时还需要的各个资源的数量,如need[i][j]表示第i个进程还需要的Rj的资源的数目,显然:need[i][j]=max[i][j]-allocation[i][j];
算法步骤
假设系统中有三类资源A,B,C,各个资源的数目已知,若此时进程Pi向系统申请资源,其资源申请向量为requesti(x,y,z),即进程i需要A类资源数目x,B类资源数目y,C类资源数目z
- 第一步若requesti>need[i](只要存在j,使得requesti[j]>need[i][j],那么此不等式便成立) ,则表明进程i所申请的资源数目大于其一开始所声明的最大值,系统对其请求不予理睬,若此不等式不成立,则继续执行下一步;
- 第二步根据allocation数组计算出available,如果request>available(只要存在j,使得requesti[j]>available[j],那么此不等式便成立) ,若该不等式成立则表明此时系统中的剩余资源数目不能满足进程i的请求,进程i必须阻塞等待,若该不等式不成立则继续执行下一步;
- 第三步,尝试着将进程i所需要的资源分配给进程i,然后检测若将进程i所需要的资源分配给进程i之后会不会导致系统进入不安全的状态,若不会导致系统进入不安全状态,那么就正式将资源分配给进程i,否则就要将刚刚尝试分配给进程i的资源回收,拒绝进程i的资源请求
上诉算法最关键的一部是最后一步的判断此时系统是否处于安全状态,于是接着介绍系统安全性检测算法
安全性检测算法
- 设置数组work[ ],work数组的初始值是available
- 将work[i]数组与need[i[进行比较,若满足work[i]>need[i]那么边将进程i添加到安全序列里面,若不满足则继续扫面下一个进程是否满足此不等式,若满足,则改变work数组的值:work[j]+=allocation[i][j],然后从第一个进程开始扫描,看当改变了work之后是否新增进程满足条件
- 若最后安全序列中含有系统中全部的进程那么就说此时系统是安全的
算法源代码
算法详细思路在代码注释中给出
cpp
#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS
//需要解决的问题:
//1.根据系统现在的状态判断系统现在是不是安全的
//2.当某一个进程像系统请求资源时,判断此时系统应不应该将此资源分配给他
#define RESOURCE_NUM 3
#define PROCESS_NUM 5
#define true 1
#define false 0
//定义系统拥有的各种资源的数量
int maxResource[RESOURCE_NUM];
//定义系统中剩余可用的资源数目
int available[RESOURCE_NUM];
//定义安全检测时的work数组
int work[RESOURCE_NUM];
//定义系统中现在已经分配给各个进程的资源数目
int allocation[PROCESS_NUM][RESOURCE_NUM];
//定义各个进程对资源的最大需求量
int maxNeeds[PROCESS_NUM][RESOURCE_NUM];
//定义各个进程还需要的各个资源的数目
int stillNeeds[PROCESS_NUM][RESOURCE_NUM];
//用于定义系统中存在的安全序列
int securitySequence[PROCESS_NUM];
//isEnougth[i]表示系统中的剩余资源可以满足进程i还需要的资源数目
int isEnough[PROCESS_NUM];
//定义用于对各个数组模块进行初始化的函数
void initialize();
//用于打印目前系统的资源分配情况
void outAllocation();
//用于求解stillNeeds函数
void solveNeeds();
//用于求解系统中剩余资源数目的函数
void solveAvailable();
//定义打印安全序列的代码
void print();
//安全性检测算法
int securityTest();
//定义用于给请求进程进行资源分配的函数
int dispense();
//定义用于将分配给某个进程的资源回收的函数
int restore();
//银行家算法,用于判断当此时系统中有进程申请系统资源时能不能将其所申请的资源分配给他
void banker();
//用于记录此时是那个进程请求系统为其分配资源
int requestProcess;
//用于记录进程所请求的各种系统资源的数目
int request[RESOURCE_NUM];
int main()
{
initialize();
//打印当前系统的资源分配情况
outAllocation();
printf("\n\n");
banker();
printf("\n\n");
//执行银行家算法之后由于可能给某个进程分配了资源,于是再次打印系统目前的资源分配清苦
outAllocation();
return 0;
}
void solveNeeds()
{
for (int i = 0; i < PROCESS_NUM; i++)
{
for (int j = 0; j < RESOURCE_NUM; j++)
{
stillNeeds[i][j] = maxNeeds[i][j] - allocation[i][j];
}
}
}
void solveAvailable()
{
for (int i = 0; i < RESOURCE_NUM; i++)
{
available[i] = maxResource[i];
}
for (int j = 0; j < RESOURCE_NUM; j++) //j表示列
{
for (int i = 0; i < PROCESS_NUM; i++) //i表示行
{
available[j] -= allocation[i][j];
}
}
}
void initialize()
{
//初始化系统中各个资源的数量
printf("请输入系统中各种资源的数量:\n");
for (int i = 0; i < RESOURCE_NUM; i++)
{
scanf("%d", &maxResource[i]);
}
//初始化各个进程对系统中各个资源的最大需求量
for (int i = 0; i < PROCESS_NUM; i++)
{
printf("请输入进程%d对系统中各种资源的最大需求量:\n", i);
for (int j = 0; j < RESOURCE_NUM; j++)
{
scanf("%d", &maxNeeds[i][j]);
}
}
//初始化allocation矩阵
for (int i = 0; i < PROCESS_NUM; i++)
{
printf("系统已经分配给进程%d的各种资源的数量:\n", i);
for (int j = 0; j < RESOURCE_NUM; j++)
{
scanf("%d", &allocation[i][j]);
}
}
//初始化需求矩阵
solveNeeds();
//初始化available数组
solveAvailable();
//初始化work数组
for (int i = 0; i < RESOURCE_NUM; i++)
{
work[i] = available[i];
}
//初始化isEnough数组
for (int i = 0; i < PROCESS_NUM; i++)
{
isEnough[i] = false;
}
printf("请输入当前是哪一个进程在向系统申请资源\n");
scanf("%d", &requestProcess);
printf("请输入进程%d向系统申请的各个资源的数目\n", requestProcess);
for (int i = 0; i < RESOURCE_NUM; i++)
{
scanf("%d", &request[i]);
}
}
void outAllocation()
{
printf("**************************************************************************************************\n");
printf("当前系统的资源分配情况如下:\n");
printf("\t\tmaxNeeds\t\tallocation\t\tstillNeeds\t\tavailable\n");
printf("资源名称\t");
for (int i = 0; i < 4; i++)
{
if (i == 3)
{
for (int j = 0; j < RESOURCE_NUM; j++)
{
printf("%d ", available[j]);
}
}
else
{
printf("A B C");
printf("\t\t\t");
}
}
printf("\n");
for (int j = 0; j < PROCESS_NUM; j++)
{
printf("P%d\t\t",j);
for (int k = 0; k < RESOURCE_NUM; k++)
{
printf("%d ", maxNeeds[j][k]);
}
printf("\t\t\t");
for (int k = 0; k < RESOURCE_NUM; k++)
{
printf("%d ", allocation[j][k]);
}
printf("\t\t\t");
for (int k = 0; k < RESOURCE_NUM; k++)
{
printf("%d ", stillNeeds[j][k]);
}
printf("\n");
}
printf("**************************************************************************************************\n");
}
void print()
{
for (int i = 0; i < PROCESS_NUM; i++)
{
if (i == PROCESS_NUM - 1)
printf("%d", securitySequence[i]);
else
printf("%d->", securitySequence[i]);
}
printf("\n");
}
int securityTest()
{
int count = 0; //用于记录安全序列中已经添加了多少个进程
for (int i = 0; i < PROCESS_NUM; i++)
{
int flag = 1; //用于标记是否使用break语句跳出了内层循环
for (int j = 0; j < RESOURCE_NUM; j++)
{
if (work[j] < stillNeeds[i][j])
{
flag = 0;
break;
}
}
//若isEnough[i]=0表示此时的进程i还没有被加入到安全序列中,那么便可以将其加入到安全序列中
if (flag == 1 && isEnough[i] == false)
{
//将进程i添加到安全序列中
securitySequence[count] = i;
count++;
//修改isEnough[i]的值为true,有两层含义,第一层含义是代表此时进程i已经进入安全序列了,下一次循环检测时若检测到进程i便可以不用重复将其加入到安全序列中
//第二层含义,是最后用于判定系统是否安全的依据,只有isEnough数组中全部的元素的值都是1才代表着此系统是安全的否则系就处于不安全的状态
isEnough[i] = true;
//当安全序列中新增进程之后,需要改变available数组的值
for (int k = 0; k < RESOURCE_NUM; k++)
{
work[k] += allocation[i][k];
}
i = -1;
//保证可以从头开始遍历所有的进程
//注意此条语句的位置必须位于此,因为只有安全序列中添加了新元素之后,available数组的值才会改变,此时才需要重新扫描所有进程看如今系统中剩余的资源是否可以满足以前不能满足的进程
}
}
//检查系统此时是否处于安全状态
for (int i = 0; i < PROCESS_NUM; i++)
{
if (isEnough[i] == false) {
return false;
}
}
return true;
}
int dispense()
{
//尝试将资源分配给请求进程的时候,发生改变的数组有,allocation,stillNeeds,available,work;
for (int i = 0; i < RESOURCE_NUM; i++)
{
allocation[requestProcess][i] += request[i];
stillNeeds[requestProcess][i] -= request[i];
available[i] -= request[i];
work[i] -= request[i];
}
}
int restore()
{
for (int i = 0; i < RESOURCE_NUM; i++)
{
allocation[requestProcess][i] -= request[i];
stillNeeds[requestProcess][i] += request[i];
available[i] += request[i];
work[i] += request[i];
}
}
void banker()
{
//第一步检查进程所申请的资源数目是否超过其一开始声明的最大值
for (int i = 0; i < RESOURCE_NUM; i++)
{
if (request[i] > stillNeeds[requestProcess][i])
{
printf("进程%d所申请的资源已经超过了其一开始定义的最大值,不予分配\n");
return;
}
}
//第二检查系统中剩余的资源是满足进程的请求
for (int i = 0; i < RESOURCE_NUM; i++)
{
if (request[i] > available[i])
{
printf("系统资源不足,分配失败,请进程阻塞等待\n");
return;
}
}
//尝试分配资源
dispense();
//分配完资源之后判断系统是否处于安全状态,若处于安全状态则就真正的将资源分配给请求的进程,否则就将刚才预分配的资源恢复
if (securityTest())
{
printf("此次分配不会导致系统进入不安全状态,分配成功!\n");
//输出此时的安全序列
printf("此时系统的其中一个安全序列为:\n");
print();
return;
}
else
{
printf("此次分配将会使得系统进入不安全状态,拒绝分配\n");
restore();
return;
}
}