1.1概述
银行家算法是一种最有代表性的避免死锁的算法。把操作系统看作是银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求分配资源相当于用户向银行家贷款。操作系统按照银行家制定的规则为进程分配资源,当进程首次申请资源时,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足它的最大需求量则按当前的申请量分配资源,否则就推迟分配。当进程在执行中继续申请资源时,先测试该进程已占用的资源数与本次申请的资源数之和是否超过了该进程对资源的最大需求量。若超过则拒绝分配资源,若没有超过则再测试系统现存的资源能否满足该进程尚需的最大资源量,若能满足则按当前的申请量分配资源,否则也要推迟分配。
本次课程设计通过用C语言编写和调试实现银行家算法的程序,达到进一步掌握银行家算法,理解系统产生死锁的原因以及系统避免死锁的方法,增强理论联系实际的能力的目的。
1.2研究意义
在多道程序系统中,多个进程的并发执行来改善系统的资源利用率,提高系统的吞吐量,但可能发生一种危险——死锁。所谓死锁(Deadlock),是指多个进程在运行过程中因争夺资源而造成的一种僵局(DeadlyEmbrace),当进程处于这种状态时,若无外力作用,他们都无法在向前推进。要预防死锁,有摒弃“请求和保持”条件,摒弃“不剥夺”条件,摒弃“环路等待”条件等方法。但是,在预防死锁的几种方法之中,都施加了较强的限制条件;而在避免死锁的方法中,所施加的限制条件较弱,有可能获得令人满意的系统性能。在该方法中把系统状态分为安全状态和不安全状态,便可避免死锁的发生。
而最具代表性的避免死锁的算法,便是Dijkstra的银行家算法。利用银行家算法,我们可以来检测CPU为进程分配资源的情况,决定CPU是否响应某进程的的请求并为其分配资源,从而很好避免了死锁的产生。
2需求分析
2.1题目描述
银行家算法是一种最具有代表性的避免死锁的算法。
要解释银行家算法,必须先解释操作系统的安全状态和不安全状态。
所谓安全状态,是指系统能按照某种进程顺序{P1,P2,…,Pn}(称{P1,P2,…,Pn }序列为安全序列),来为每个进程Pi分配其所需资源,直至满足每个进程对资源的最大需求,使每个进程都可以顺利完成。安全状态一定没有死锁发生。
如果系统无法找到这样一个安全序列,则称系统处于不安全状态。
那么,什么是安全序列呢?
如果对每一个进程Pi(1 2.2基本要求
(1)设计用来保存:可利用资源向量Available、最大需求矩阵 Max、分配矩阵 Allocation 、需求矩阵 Need。
(2)编写银行家算法,安全性检查算法。要求在不安全时输出错误信息。
(3)编写输出函数,能对进程
2.3目的
根据设计题目的要求,充分地分析和理解题目,叙述系统的要求,明确程序要求实现的功能以及限制条件。明白自己需要用代码实现的功能,清楚编写每部分代码的目的,做到有的放矢,有条理不遗漏的用代码实现银行家算法。
3概要设计
3.1设计思路
先对用户提出的请求进行合法性检查,即检查请求是否大于需要的,是否大于可利用的。若请求合法,则进行预分配,对分配后的状态调用安全性算法进行检查。若安全,则分配;若不安全,则拒绝申请,恢复到原来的状态,拒绝申请。
3.2银行家算法步骤
(1)如果Requesti<or=Need,则转向步骤(2);否则,认为出错,因为它所需要的资源数已超过它所宣布的最大值。
(2)如果Request<or=Available,则转向步骤(3);否则,表示系统中尚无足够的资源,进程必须等待。
(3)系统试探把要求的资源分配给进程Pi,并修改下面数据结构中的数值:Available=Available-Request[i];
Allocation=Allocation+Request;
Need=Need-Request;
(4)系统执行安全性算法,检查此次资源分配后,系统是否处于安全状态。
3.3安全性检查算法步骤
(1)设置两个向量
①工作向量Work。它表示系统可提供进程继续运行所需要的各类资源数目,执行安全算法开始时,Work=Allocation;
②布尔向量Finish。它表示系统是否有足够的资源分配给进程,使之运行完成,开始时先做Finish[i]=false,当有足够资源分配给进程时,令Finish[i]=true。
(2)从进程集合中找到一个能满足下述条件的进程:
①Finish[i]=false
②Need< =Work;如找到,执行步骤(3);否则,执行步骤(4)。
(3)当进程P获得资源后,可顺利执行,直至完成,并释放出分配给它的资源,故应执行:
Work=Work+Allocation;
Finish[i]=true; 转向步骤(2)。
(4)如果所有进程的Finish[i]=true,则表示系统处于安全状态;否则,系统处于不安全状态。
3.4数据结构
3.4.1主要用到的数据结构
int available[];//可利用资源矩阵
int max[][];//所需资源最大量矩阵
int allocation[][];//已分配资源矩阵
int need[][];//需要资源矩阵
int request[][] = { 0 };//记录某个进程申请各个资源类中的资源实例的数量
int finish[] = { 0 };//工作变量,用于判断进程是否已经执行过,初始状态全部为0,即未执行
int p[];//记录序列执行顺序
int total[i];//记录系统资源总数
int process;//记录进程数量
int r;//记录当前要申请资源的进程的序号
int key = 1;
3.4.2程序模块
void init()//进行初始化输入的函数
void print()//输出函数
int testing()//安全性算法
int Bank() //银行家算法
int main() //程序主函数
4详细设计
4.1主要函数的核心代码
1.进行初始化输入的函数
2.输出的函数
3.利用安全性算法检测的函数
4.进行资源分配的函数
5.利用银行家算法进行判断的函数
4.2安全性检测算法流程图
4.3资源分配算法流程图
5数据测试
5.1测试数据
进程个数:3
资源种类数:2
资源总数目:7 15
每个进程最多需要资源数目 每个进程已分配资源数目
6 5 1 3
3 8 2 6
4 7 2 3
5.2运行结果
5.2.1验证安全性
5.2.2 Request<=Need,Request<=Available,请求分配成功
5.2.3 Request<=Need,Request>Available
5.2.4 Request>Need,Request<=Available
5.2.5 Request<=Need,Request<=Available,请求分配失败
6总结
此次实验的编程实现了银行家算法的功能,课程设计利用C语言编写,报告中介绍了银行家算法的背景、设计及通过编程实现银行家算法,利用银行家算法解决问题的一般步骤,通过编写程序来模拟银行家算法分配资源的过程。
操作系统的基本特征是并发、共享、虚拟及异步。系统允许多个进程并发进行,并且供其共享系统的软硬件资源。为了最大限度的利用计算机系统的资源,操作系统会采取动态分配的策略,但是这样就容易因为资源不足,分配不当导致“死锁”。而此次课程设计就是用银行家算法来避免“死锁”。银行家算法就是一个一个分配资源的过程,让分配的序列不会产生死锁。此算法的思想是按照银行家的步骤发配资源时,每次分配后总存在着一个进程,如果让它单独运行下去,必然可以获得它所需要的全部资源。
7参考文献
[1] 汤小丹,梁红兵,哲凤屏,汤子瀛.计算机操作系统. 西安:西安电子科技大学出版社,2007.
[2] 严蔚敏,吴伟民.数据结构. 北京:清华大学出版社,2006.
源代码如下:
#include
#include
#include
static int x;
typedef struct {
char name[10];
char finish[10];
}process;
void examine(int m, int n, int M[][10]) //检测是否已经输入数据!
{
int f = 0;
int k = 0;
for (int i = 0; i < m; i++)
{
f = 0;
for (int j = 0; j < n; j++)
{
if (M[i][j] == 0)
{
f++;
}
}
if (f == n)
{
k++;
}
}
if (k == m)
{
printf(" 未输入数据,请选择功能'1'输入数据!\n");
x = -1;
}
else { x = 1; }
}
void ASAalone(int m, int n, int M[][10], int Al[][10], int Av[10], process pc[]) //单独调用安全性算法
{
int max[10][10];
int Need[10][10];
int Alloction[10][10];
int work[10];
process Aquene[10];
process mistake[10];
int num = 0,number=0;
int i, j;
int k = 0,mm=0;
int kk = m;
examine(m, n, M);
if (x == -1)
{
printf(" 未输入数据!,无法调用单独调用安全性算法!\n");
}
else if (x == 1)
{
for (int i = 0; i < m; i++)
{
if (strcmp(pc[i].finish, "AAA") == 0)
{
kk--;
continue;
}
strcpy(pc[i].finish, "flase");
}
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
{
max[i][j] = M[i][j];
Alloction[i][j] = Al[i][j];
Need[i][j] = max[i][j] - Alloction[i][j];
work[j] = Av[j];
}
}
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (Need[i][j] < 0)
{
mistake[number] = pc[i];
printf(" 数据有错误,进程 %s 所需的最大资源个数小于已经分配的资源个数,即就是Need小于0!\n", mistake[j].name);
number++;
break;
}
}
}
if (number != 0)
{
printf(" 请重新输入数据:\n");
return;
}
for (int y = 0; y < m; y++)
{
for (int i = 0; i < m; i++)
{
k = 0;
for (int j = 0; j < n; j++)
{
if (Need[i][j] <= work[j])
{
k++;
}
}
if ((k == n) && (strcmp(pc[i].finish, "flase") == 0))
{
strcpy(pc[i].finish, "true");
Aquene[num++] = pc[i];
for (int m = 0; m < n; m++)
{
work[m] = work[m] + Alloction[i][m];
}
break;
}
}
}
if (num==kk)
{
printf("\n");
printf(" 系统为安全状态,安全序列为: ");
for (int i = 0; i < kk; i++)
{
printf(" %s ", Aquene[i].name);
}
printf("\n");
printf("\n");
printf("进程名 MAX资源 Allocation资源 Need资源 Available资源\n");
for (int i = 0; i < m; i++)
{
if (strcmp(pc[i].finish, "AAA") == 0)
{
continue;
}
printf("%3s", pc[i].name);
printf(" ");
for (int j = 0; j < n; j++)
{
printf("%3d", M[i][j]);
}
printf(" ");
for (int j = 0; j < n; j++)
{
printf("%3d", Al[i][j]);
}
printf(" ");
for (int j = 0; j < n; j++)
{
printf("%3d", M[i][j] - Al[i][j]);
}
printf(" ");
for (int j = 0; j < n; j++)
{
if (i == 0)
{
printf("%3d", Av[j]);
}
}
printf("\n");
}
}
else {
printf(" 系统为不安全状态!\n");
}
}
}
int ASA(int m,int n,int M[][10],int Al[][10],int Av[10],process pc[], int Re[],int f) //安全性算法 //安全算法
{
int max[10][10];
int Need[10][10];
int Alloction[10][10];
int Requst[10];
int work[10];
process Aquene[10];
process mistake[10];
int num = 0,number=0;
int k = 0;
if (strcmp(pc[f].finish, "AAA") == 0)
{
printf(" 进程%s已经被释放!\n", pc[f].name);
return -9;
}
for (int i = 0; i < m; i++)
{
if(strcmp(pc[i].finish,"AAA")==0)
{
continue;
}
strcpy(pc[i].finish, "flase");
}
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{ max[i][j] = M[i][j];
Alloction[i][j] = Al[i][j];
Need[i][j] = max[i][j] - Alloction[i][j];
Requst[j] = Re[j];
work[j] = Av[j];
}
}
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (Need[i][j] < 0)
{
mistake[number] = pc[i];
number++;
break;
}
}
}
if (number == 0)
{
int H = 0;
int P = 0;
for (int i = 0; i < n; i++)
{
if ((Need[f][i] >= Requst[i]))
{
H++;
}
else
{
printf(" 请求的资源个数大于所需的资源个数,即Need);
break;
}
}
if (H == n)
{
for (int i = 0; i < n; i++)
{
if (work[i] >= Requst[i])
{
P++;
}
}
}
else { return 3; }
if (P == n)
{
for (int i = 0; i < m; i++) //加入Requst后,更改数据
{
work[i] = work[i] - Requst[i];
Alloction[f][i] = Alloction[f][i] + Requst[i];
Need[f][i] = max[f][i] - Alloction[f][i];
}
for (int y = 0; y < m; y++) //找安全序列
{
for (int i = 0; i < m; i++)
{
k = 0;
for (int j = 0; j < n; j++)
{
if (Need[i][j] <= work[j])
{
k++;
}
}
if ((k == n) && (strcmp(pc[i].finish, "flase") == 0))
{
strcpy(pc[i].finish, "true");
Aquene[num++] = pc[i];
for (int m = 0; m < n; m++)
{
work[m] = work[m] + Alloction[i][m];
}
break;
}
}
}
if (num == m)
{
printf("\n");
printf(" 系统为安全状态,安全序列为: ");
for (int i = 0; i < m; i++)
{
printf(" %s ", Aquene[i].name);
}
return 0;
}
else {
printf(" 系统为不安全状态!\n");
return -1;
}
}
else
{
printf(" 所申请的的资源个数大于系统现有的资源个数,即 Available);
return 2;
}
}
else {
for (int j = 0; j < number; j++)
{
printf(" 数据有错误,进程 %s 所需的最大资源个数小于已经分配的资源个数!\n", mistake[j].name);
}
printf(" 请重新输入数据:\n");
return 5;
}
}
void BankersAlgorithm(int m,int n, int M[][10], int Al[][10], int Av[10], process pc[]) //银行家算法
{
int Requst[10];
char name[10];
int k,b=0,mm=0;
examine(m, n, M);
if (x ==-1)
{
printf(" 未输入数据!,无法调用银行家算法\n");
}
else if (x == 1)
{
printf(" 请输入所申请资源的进程名:");
scanf("%s", name);
for (int i = 0; i < m; i++)
{
if (strcmp(pc[i].name, name) == 0)
{
k = i;
break;
}else
{
b++;
}
}
if (b == m)
{
printf(" 查无此进程,请重新输入: \n");
}
else
{
printf(" 找到进程,所申请的资源数目:");
for (int i = 0; i < n; i++)
{
scanf("%d", &Requst[i]);
}
int i = ASA(m, n, M, Al, Av, pc, Requst, k); //调用安全性算法
if (i == 0)
{
for (int i = 0; i < n; i++)
{
Al[k][i] = Al[k][i] + Requst[i];
Av[i] = Av[i] - Requst[i];
}
for (int i = 0; i < n; i++)
{
if (Al[k][i]== M[k][i])
{
mm++;
}
}
printf("\n");
if (mm == n)
{
printf("进程%s所需要的资源个数已经得到满足,对其进行释放!\n",pc[k].name);
strcpy(pc[k].finish, "AAA");
for (int i = 0; i < n; i++)
{
Av[i] = Al[k][i]+ Av[i];
}
}
printf("\n");
printf("进程名 MAX资源 Allocation资源 Need资源 Available资源\n");
for (int i = 0; i < m; i++)
{
if (i == k)
{
continue;
}
printf("%3s", pc[i].name);
printf(" ");
for (int j = 0; j < n; j++)
{
printf("%3d", M[i][j]);
}
printf(" ");
for (int j = 0; j < n; j++)
{
printf("%3d", Al[i][j]);
}
printf(" ");
for (int j = 0; j < n; j++)
{
printf("%3d", M[i][j] - Al[i][j]);
}
printf(" ");
for (int j = 0; j < n; j++)
{
if (i == 0)
{
printf("%3d", Av[j]);
}
}
printf("\n");
}
printf("\n");
printf(" 资源分配成功!\n");
}
else if (i == -1)
{
printf(" 资源分配失败! \n");
printf("进程名 MAX资源 Allocation资源 Need资源 Available资源\n");
for (int i = 0; i < m; i++)
{
printf("%3s", pc[i].name);
printf(" ");
for (int j = 0; j < n; j++)
{
printf("%3d", M[i][j]);
}
printf(" ");
for (int j = 0; j < n; j++)
{
printf("%3d", Al[i][j]);
}
printf(" ");
for (int j = 0; j < n; j++)
{
printf("%3d", M[i][j] - Al[i][j]);
}
printf(" ");
for (int j = 0; j < n; j++)
{
if (i == 0)
{
printf("%3d", Av[j]);
}
}
printf("\n");
}
}
}
}
}
void List() //目录
{
printf("--------------------------\n");
printf("---0.退出-----------------\n");
printf("---1.输入进程及其数据-----\n");
printf("---2.银行家算法调用-------\n");
printf("---3.安全性算法-----------\n");
printf("---4.改变进程数及资源数---\n");
printf("--------------------------\n");
}
void input(process pc[], int m, int n, int M[][10], int Al[][10],int Av[10]) //进程的数据输入
{
int transit[10] = { 0 }; //过渡数组,用来计算Available数组
printf("请输入总资源个数: ");
int MAX[10];
for (int i = 0; i < n; i++)
{
scanf("%d", &MAX[i]);
}
for (int i = 0; i < m; i++)
{
printf("请输入进程名");
scanf("%s", pc[i].name);
strcpy(pc[i].finish, "flase");
printf(" ");
printf("请输入MAX资源: ");
for (int j = 0; j < n; j++)
{
scanf("%d", &M[i][j]);
}
printf(" ");
printf("请输入Alloction资源:");
for (int j = 0; j < n; j++)
{
scanf("%4d", &Al[i][j]);
}
}
for (int j = 0; j < n; j++)
{
for (int i = 0; i < m; i++)
{
transit[j] = transit[j] + Al[i][j];
}
}
for (int i = 0; i < n; i++)
{
Av[i] = MAX[i] - transit[i];
}
printf("进程名 MAX资源 Allocation资源 Need资源 Available资源\n");
for (int i = 0; i < m; i++)
{
printf("%3s", pc[i].name);
printf(" ");
for (int j = 0; j < n; j++)
{
printf("%3d", M[i][j]);
}
printf(" ");
for (int j = 0; j < n; j++)
{
printf("%3d", Al[i][j]);
}
printf(" ");
for (int j = 0; j < n; j++)
{
printf("%3d", M[i][j] - Al[i][j]);
}
printf(" ");
for (int j = 0; j < n; j++)
{
if (i == 0)
{
printf("%3d", Av[j]);
}
}
printf("\n");
}
//printf("请输入程序现有的资源数目:");
// for (int i = 0; i < n; i++)
// {
// scanf("%d", &Av[i]);
// }
}
void Choose(int k, int M[][10], int Al[][10],process pc[],int Av[10],int m,int n)
{
switch (k)
{
case 0:printf("退出程序!\n"); break;
case 1:input(pc,m,n,M,Al,Av); break;
case 2:BankersAlgorithm(m,n,M,Al,Av,pc);break;
case 3:ASAalone(m, n, M,Al,Av, pc); break;
case 4:break;
default:printf("输入无效,请重新输入!\n"); break;
}
}
int main()
{
int m, n,k,l=0;
int max[10][10] = { {7,5,3},{3,2,2},{9,0,2},{2,2,2},{4,3,3} };
int Need[10][10];
int Alloction[10][10] = { {0,1,0}, {2,0,0}, {3,0,2}, {2,1,1}, {0,0,2} };
int Available[10] = { 3,3,2 };
process pc[10] = { {"p0","flase"},{"p1","flase"},{"p2","flase"},{"p3","flase"},{"p4","flase"} }; //进程名
/*int max[10][10] = { 0 };
int Need[10][10];
int Alloction[10][10] = { 0 };
int Available[10] = { 0 };
process pc[10] = { {"p0","flase"},{"p1","flase"},{"p2","flase"},{"p3","flase"},{"p4","flase"} };*/
printf("请输入进程个数: ");
scanf("%d", &m);
printf("请输入资源种类个数: ");
scanf("%d", &n);
do{
List();
printf("请输入选择:");
scanf("%d", &k);
Choose(k, max, Alloction,pc, Available,m,n);
printf("\n");
if (k == 4)
{
printf("请输入进程个数: ");
scanf("%d", &m);
printf("请输入资源种类个数: ");
scanf("%d", &n);
printf("由于你修改了进程数及其资源数,请选择‘1’重新输入!\n");
}
} while (k != 0);
return 0;
}