银行家算法
疫情 期间,上操作系统原理课,因为在家,所以上的浑浑噩噩,上周老师让提交银行家算法实验报告,自己看书弄了挺长时间的基本实现课本(汤小丹老师)上的案例,为了锻炼自己使用Markdown的能力,写下这篇文章。
1、银行家算法的详解
这方面我就不多介绍(因为时间问题,来不及作图),在csdn上看到几篇博客,写的很详细。
2、银行家算法的代码实现
按照课本上算法的描述实现算法的时候,自己起初出了一些问题。我们知道,银行家算法的核心
是安全性检查算法:当我们申请调用资源给某个进程 i 的时候,系统会先试探性地将资源分配给进程 i,
然后调用安全性检查算法,查询是此时是否存在安全序列,如果存在的话,那么表示这次资源的分配是没
有问题的,如果不存在安全序列,则表示此次资源的申请是危险的,回收已分配的资源,并让进程 i等待
1、改进
首次实现算法的时候,在安全性算法那里与大多数人的想法一样,套用两次循环来寻找满足
条件(Finish[i]=0&&Work[i]<=Need[i][j])的进程,这样每返回一个可用进程下标的时候,总是会
在进程起始位置搜寻,坏的情况下,要进行n次if查询。虽然安全序列的不同·对于整个银行家算法的实现
并无影响,但是我们始终哟注重时间效率。我在安全性检查方面借助了队列和栈。这虽然在增加空间代价,
但是可减少判断的次数。
(1)、栈思路:第一次不满足条件的进程入栈,先进去的进程最后出来 设计两个栈,一个是“等待栈”,用于存放第一次查询的时候不满足条件的进程,如果不满足要求,就
将该进程的下标压入等待栈中。那么循环下来之后,如果栈满的话,可以判定没有安全序列,如果有的话
就从等待栈中Pop一个进程,再次查询,如果不满足的话,我们在建立一个“副等待栈”,这个栈可以单独
设立,也可以起初的时候把进程就放在栈中,那么一轮循环下来,进程栈就空了,这时候就可以当作副等待
栈了,处理过程与等待栈的处理过程和思路一样。
(2)、队思路:第一次不满足条件的进程入队,先进去的进程先出来
这个思路就用队的方式来解决,代码没有来得及编写,大致与栈一致
代码实现:代码不精,乱七八糟,正在努力
注:下面代码中有两个findindex函数,一个是用栈实现的,另一个是瞎写的。
当时看错算法内容了,以为是在安全性检查中,使不符合条件的进程等待。实际上无论安全性检查算法是怎么设计的,只要有安全序列就可以了。
#include<iostream>
using namespace std;
/*
*定义一个顺序栈
*/
typedef struct
{
int *top;//栈顶指针
int *base;//栈底指针
int stacksize;//定义栈的大小
}SqStack;
/*
*初始化栈
*/
int initStack(SqStack &L,int n)
{//n代表栈的初始长度
L.base = new int[n];
if (!L.base)
return 0;//如果创建栈失败,那么返回0
L.top = L.base;//栈底与栈顶在同一位置,空栈
L.stacksize = n;
return 1;
}
/*
*Push 入栈,e代表被压入栈的内容
*/
int IsFull(SqStack L)
{
if (L.top - L.base == 0)
return 1;
return 0;
}
//入栈
int Push(SqStack& L,int e)
{
if (L.top-L.base==L.stacksize)
{
cout << "压栈失败,进程号:"<<e<< endl;
return 0;//表示栈满
}
*L.top = e;
L.top++;
return 1;
}
//出栈
int Pop(SqStack& L, int &e)
{
if (L.top - L.base == 0)
{
cout << "出栈失败,这是空栈" << endl;
return 0;//这是空栈
}
L.top--;
e = *L.top;
return 1;
}
//测试当前栈的实际长度
int getLength(SqStack L)
{
return L.top - L.base;
}
#define Process_Num 5
#define Source_Num 3
int NUM = 0;
int Available[Source_Num] = { 3,3,2 };//this is available source_num
int Max[Process_Num][Source_Num] = {
{7,5,3},
{3,2,2},
{9,0,2},
{2,2,2},
{4,3,3}
};//this is the max source_num
int Allocation[Process_Num][Source_Num] =
{
{0,1,0},
{2,0,0},
{3,0,2},
{2,1,1},
{0,0,2}
};//this is the haved allocate source_num
int Need[Process_Num][Source_Num] =
{
{7,4,3},
{1,2,2},
{6,0,0},
{0,1,1},
{4,3,1}
};//这是当前进程所需要的资源的总数目
//int Request[Process_Num];//表示每个进程每次要申请访问的资源的数目
int Work[Source_Num];//在安全性检查算法中使用
int Finish[Process_Num];//安全性检查算法中使用,判断每个进程是否安全
int Resiger[Source_Num];//用于保存下标
/******* 函数区 *************/
int banker();//银行家算法
int isSafe();//安全性算法
int lh[Process_Num];//辅助数组
int findIndex();//在安全性检查算法中,寻找可以被分配资源的进程的下标
void show_one(int A[], int n);//打印一维函数所有值
int finish_true(int Finish[], int n);//判断安全性算法中的Finish函数是否全为true
int finish_false(int Finish[], int n);//判断安全性算法中的Finish函数是否全为false
int isEqual(int A[], int m, int B[]);//若对于任何 i B[i]>=A[i],return 1,否则返回0
void show_two();//显示函数
int find_zero(int A[], int m, int n);
int find_design(int A[], int n);
SqStack L1, L2, L;//L1:等待栈,L:存放进程栈,L2:进程栈的辅助栈
int main()
{
if (banker() > -1)
cout << "Successful,已经分配给进程。" << endl;
int i, k;
char m;
do
{
k = banker();
cout << endl;
if (k >= 0 && finish_false(Need[k], Source_Num))
{
cout << "Successful 已经分配资源给进程 " << k << ",并且进程已完成并释放资源" << endl;
for (int j = 0; j < Source_Num; j++)
{
Available[j] = Available[j] + Allocation[k][j];
Allocation[k][j] = 0;
}
show_two();
}
else if (k >= 0 && !finish_false(Need[k], Source_Num))
{
cout << "Successful 已经分配资源给进程 " << k << ",但进程没有完成并释放资源" << endl;
show_two();
}
else
cout << "Default 分配资源给进程失败,请重新选择进程以及申请的资源" << endl;
cout << "如果你想继续,请输入Y/y,否则输入N/n" << endl;
cin >> m;
if (m == 'Y' || m == 'y')
i = 1;
else if (m == 'N' || m == 'n')
i = 0;
cout << "******************************************" << endl;
} while (i);
return 0;
}
int banker()
{//表示一次的进程进行资源申请,如果这次申请成功那么返回1,否则返回0
int i, j, k, m;//i代表进程数,j代表资源地数目
int Request[Source_Num];//作为临时数组
show_two();
cout << "正在检查T0时刻的安全性........" << endl;
if (!isSafe())
{
cout << "T0时刻不安全,请重新分配......" << endl;
exit(0);
}
cout << endl;
printf("请输入请求资源的进程号 0--4,编号为:");
cin >> i;
m = i;
cout << endl;
printf("请输入进程 %d 要申请的各类资源的数目\n", i);
cout << endl;
for (j = 0; j < Source_Num; j++)
{
printf("第 %d 号资源申请数量:", j);
cin >> Request[j];
cout << endl;
}
cout << "Request请求资源数目为:" << endl;
cout << " A B C" << endl;
show_one(Request, Source_Num);//打印数组
cout << endl;
/*判断该进程所申请资源的数量是否合理*/
for (j = 0; j < Source_Num; j++)
if (Request[j] > Need[i][j])
{
cout << "No:申请资源的数量超过进程最大需要的的数量" << endl;
return -1;//如果申请错了,那么直接终止这次资源的申请
}
cout << "YES:申请资源的数量未超过进程最大需要的的数量" << endl;
if (isEqual(Request, Source_Num, Available))
{//表示request<Available
for (j = 0; j < Source_Num; j++)
{
Available[j] = Available[j] - Request[j];
Allocation[i][j] = Allocation[i][j] + Request[j];
Need[i][j] = Need[i][j] - Request[j];
}
cout << "*************************************************" << endl;
show_two();
cout << "******************正在进行安全性检查*********************" << endl;
if (!isSafe())
{//表示此次分配不安全,就将已分配的资源恢复
//表且还要将该进程等待
for (j = 0; j < Source_Num; j++)
{
Available[j] = Available[j] + Request[j];
Allocation[i][j] = Allocation[i][j] - Request[j];
Need[i][j] = Need[i][j] + Request[j];
}
cout << "Sorry 当前申请不安全" << endl;
return -1;
}
else
{
//show_two();
return m;//表示此进程分配成功
}
}
else
{
cout << "Default! 系统不能提供这么多资源" << endl;
return -1;
}
}
void show_one(int A[], int n)
{//这是一个打印出一维数组所有值的函数
int i;
if (n <= 0)
return;
cout << " ";
for (i = 0; i < n; i++)
{
printf("%d ", A[i]);
}
}
void show_two()
{
int i, j;
cout << "**************************************资源分配情况*******************************************" << endl;
cout << "| 资源情况 work allocation need Available |" << endl;
cout << "| 进程 A B C A B C A B C A B C |" << endl;
for (i = 0; i < Process_Num; i++)
{
cout << " " << i << " ";
for (j = 0; j < Source_Num; j++)
{
cout << " " << Max[i][j];
}
cout << " ";
for (j = 0; j < Source_Num; j++)
{
cout << " " << Allocation[i][j];
}
cout << " ";
for (j = 0; j < Source_Num; j++)
{
cout << " " << Need[i][j];
}
cout << " ";
for (j = 0; j < Source_Num; j++)
{
if (i == 0)
cout << " " << Available[j];
}
cout << endl;
}
}
int isSafe()
{
int i;
if (!initStack(L1, Process_Num))
{
cout << "Sorry!!! 等待栈L1初始化错误,程序即将退出" << endl;
return -1;
}
if (!initStack(L, Process_Num))
{
cout << "Sorry!!! 进程栈L初始化错误,程序即将退出" << endl;
return -1;
}
//为进程栈存放进程
for (i = Process_Num - 1; i >= 0; i--)
Push(L, i);//倒序压入进程栈中
int j, k;//i 代表进程的计数器,j代表资源的计数器
for (j = 0; j < Source_Num; j++)
Work[j] = Available[j];
for (i = 0; i < Process_Num; i++)
Finish[i] = 0;
cout << "安全序列:";
while ((k = findIndex()) >= 0)
{
cout << k << "--->";
for (j = 0; j < Source_Num; j++)
Work[j] = Work[j] + Allocation[k][j];//释放资源
Finish[k] = 1;
if (finish_true(Finish, Process_Num))
{//表示Finish全为true(1)
delete[]L.base;
delete[]L1.base;
delete[]L2.base;
return 1;//表示安全
}
}
delete []L.base;
delete []L1.base;
delete []L2.base;
return 0;//表示不安全
}
int findIndex()
{
int i, j, e;
while (!IsFull(L))
{//这里是进程循环
if (!Pop(L, i))
{//从进程栈中取栈
cout << "L栈出栈失败,进程号:" << i << endl;
return -1;
}
j = 0;
while (1)
{//这里是资源循环,我们用j来判断资源能否满足进程i当j=Source_Num时,满足,小于时不满足
if (Finish[i] == 0 && Need[i][j] <= Work[j])
j++;
else
{
//Pop(L, e);
Push(L1,i);//压入栈中
break;
}
if (j == Source_Num)
{
return i;
}
}
if (j == Source_Num)
{
return i;
}
}
//跳出上面while循环,表示进程栈L为空,那么此时我们需要检查等待栈的情况
int n = getLength(L1);//nb表示等待栈的长度
if (!initStack(L, n))
{
cout << "Sorry!!! 辅助栈L2初始化错误,程序即将退出" << endl;
return -1;
}
while (!IsFull(L1) || getLength(L2) != n)
{//此时等待栈中有进程在等待
Pop(L1, i);//出栈并传递给i
j = 0;
while (1)
{
if (Finish[i] == 0 && Need[i][j] <= Work[j])
j++;
else
{
Push(L2, i);
}
if (j == Source_Num)
{
return i;
}
}
if (j == Source_Num)
{
return i;
}
if (IsFull(L1) && getLength(L2) != n)
{//此时表示,辅助栈未满而等待栈空闲
Pop(L2, e);
Push(L1, e);//这里作为一个调回
}
}
}
int isEqual(int A[], int m, int B[])
{//判断两个一维数组的的值是否相等,若A有一项大于B,返回0
//若B的任何一项都大于等于A中对应的,那么返回 1
int i;
for (i = 0; i < m; i++)
if (A[i] > B[i])
return 0;
return 1;
}
int finish_true(int Finish[], int n)
{//判断finish数组的值是否全为 true,若是则返回 1,不是返回0
int i;
int k = 0;
for (i = 0; i < n; i++)
{
if (Finish[i] == 1)
k = k + 1;
else
k = k - 1;
}
if (k == 5)
return 1;
else
return 0;
}
int finish_false(int Finish[], int n)
{//判断finish数组的值是否全为 true,若是则返回 1,不是返回0
int i;
int k = 0;
for (i = 0; i < n; i++)
{
if (Finish[i] == 0)
k = k + 1;
else
k = k - 1;
}
if (k == 5)
return 1;
else
return 0;
}
/*
*findIndex @v2.0
*要求在某一个进程不能
*/
int findIndex_()
{//返回进程的编号
int i, j, k, i_;
i = 0;
/*if (n == -1)//n就是上次的下标,如果为 -1表示这是第一次
i = 0;
else if (n == Process_Num - 1)
i = 0;//表示最后一个完成,要开始第二轮的循环
else if (n >= 0 || n < Process_Num - 1)
i = n;*/
i = find_design(Finish, Process_Num);
while (i <= 4)
{
j = 0;//j作为资源的计数器,每一次都需要
//k = find_design(lh, Process_Num);//k作为返回下
while (1)
{
if (Finish[i] == 0 && Need[i][j] <= Work[j])
{
j++;
}
else {//如果当前按k不满足条件,置其在lh中为1
//k = find_design(lh,Process_Num);
//lh[i] = 1;
break;//结束本次的循环
}
if (j == Source_Num)
{
return i;//返回进程的下标
}
}
if (j == Source_Num)
{
return i;//返回进程的下标
}
i++;
}
return -1;
}
//在搜索下标函数中,如果在一次安全ixng算法A中
//进程i满足条件,那么下一次寻找时,开始的下标j要满足以下条件之一
//(1)j>i且j之后的进程没有被被释放
//(2)j=0
int find_design(int A[], int n)
{
int i, j, index_r, num;
index_r = -1;
num = 0;
for (i = 0; i < n; i++)
{
if (A[i] == 0 && A[n - 1] == 0)
{
index_r = i;
if (find_zero(A, i, n - 1))
{//表示I后面全为0,满足条件1
break;
}
}
if (A[i] == 0 && A[n - 1] == 1)
{
index_r = i;
break;
}
}
if (i == (Process_Num - 1) && A[i] == 0)
{//表示已经搜寻一圈,到达最后一列
for (j = 0; j < 3; j++)
if (Need[i][j] <= Work[j])
num++;
if (num == 3)
{
//表示最后一个进程安全
return i;//可以直接返回
}
else
{//最后一个进程不安全,并且从头开始没有全为0的,那么从0开始,见到一个0
//就返回
/*if (!find_zero(A, 0, n - 1))
{
for (i = 0; i < n; i++)
if (A[i] == 0)
return i;
}
else*/
return 0;
}
}
if (index_r == -1)
{
cout << "没有找到,不满足条件1" << endl;
return -1;
}
else
return index_r;
}
int find_zero(int A[], int m, int n)
{//判断A数组,[m,n]之间内有没有全0,
//如果有,返回 1.否则,返回 0;
int i, j;
j = 0;
for (i = m + 1; i <= n; i++)
{
if (A[i] == 0)
j++;
else
j--;
}
if (j != (n - m))
return 0;
else
return 1;
}