目录
1 实验名称
死锁的避免
2 实验目的
通过使用银行家算法实现系统资源的分配和安全性检查模拟,深刻理解操作系统的死锁避免算法。
3 实验内容
C语言完成“银行家算法”,记录程序运行结果,完成实验报告。要求:
1)设计五个进程{P0,P1,P2,P3,P4}共享三类资源{A,B,C}的系统,{A,B,C}的资源总数量分别为10,5,7。
2)并发进程可动态地申请资源和释放资源(程序交互输入申请或释放资源数量),系统按各进程的申请动态地分配资源。
3)每当进程动态申请资源或释放资源时,模拟程序应能及时输出各个进程在此时刻的资源分配表、系统可用资源量和安全序列等资源分配信息和安全检查信息。
4 实验原理及流程图
银行家算法:进程可动态的申请和释放资源,系统按照各进程的申请动态地分配资源,在T0时刻的资源分配情况如下表:
1 | Name | Max | Allocation | Need | Available |
2 | P0 | 7,5,3 | 0,1,0 | 7,4,3 | 3,3,2 |
3 | P1 | 3,2,2 | 2,0,0 | 1,2,2 | |
4 | P2 | 9,0,2 | 3,0,2 | 6,0,0 | |
5 | P3 | 2,2,2 | 2,1,1 | 0,1,1 | |
6 | P4 | 4,3,3 | 0,0,2 | 4,3,1 |
(1) 银行家算法的数据结构
Resource:一个长度为m向量,表示系统拥有的资源数目。
Available:一个长度为m向量,表示每类资源的可用数目。
Max:一个m×n矩阵,定义每个进程的最大资源需求数。
Allocation:一个m×n矩阵,定义当前分配给每个进程每类资源的数目。
Need:一个m×n矩阵,表示每个进程还需多少资源。
(2) 实现银行家算法 设:Requesti是进程Pi的请求向量。 当Pi发出资源请求后,系统按如下步骤进行检查:
如果Request[j] Need[i][j] 则go to 2,否则认为出错。
如果Request[j] < Available[i][j] 则go to 3,否则表示无足够资源,Pi等待。
系统进行试探分配,并求该相应数据结构数据 Available:= Available- Requesti Allocationi:= Allocationi+ Requesti Needi:= Needi-Requesti
系统执行安全性算法:安全,把资源分配给Pi,否则, Pi等待。
(3) 实现安全性算法
设Work 和 Finish是长度分别为m,n的向量 初试值Work =Available ,Finishi = False(所有)
从进程集合中找到一个能满足下列条件的进程 a. Finishi= False b. Needi Work 如找到go to 3 否则 go to 4
当进程Pi 获得资源后,顺利执行,直至完成,并释放分配给它的资源。 Work = Work+ Allocationi Finishi:= True go to 2
如果所有进程的Finishi= True 则表示系统安全,否则为不安全。
流程图:
5 实验源代码
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int available[100] = { 0 };//系统中每种资源的可利用资源数
int max[100][100] = { 0 };//进程的最大需求资源数
int allocation[100][100] = { 0 };//系统刚开始每个进程已占用资源数
int need[100][100] = { 0 };//每个进程还需要的资源数
int Finish[100] = { 0 };//判断每个进程是否安全
int safeSeries[100];//安全序列号
int request[100];//进程请求资源量
int num;//资源计数变量,便于判断安全性
int work[1000];//系统当前可分配资源量
int resourseType, customerNumber;//资源种类数和进程数
int flag = 0;//作为是否输入数据的判断变量
//函数声明
int isFinish(int row);
void SafeInfo(int* work, int index);
int judSystemSecurity();
int judSystemSecurity_1();
void judRequestSecurity();
void showMenu();
void keyDown();
void InitStastic();
//函数定义
int isFinish(int row)
{
int j;
for (j = 0; j < resourseType; j++){
if (need[row][j] != 0){
return 0;
}
}
return 1;
}
//进程资源输出
void SafeInfo(int* work, int index)
{
int j;
printf(" P%d\t", index);
for (j = 0; j < resourseType; j++){
printf("%d ", work[j]);
}
printf("\t ");
for (j = 0; j < resourseType; j++){
printf("%d ", need[index][j]);
}
printf("\t ");
for (j = 0; j < resourseType; j++){
printf("%d ", allocation[index][j]);
}
printf("\t ");
for (j = 0; j < resourseType; j++){
printf("%d ", allocation[index][j] + work[j]);
}
printf("\t T");
printf("\n");
return;
}
//利用goto语句判断系统安全性
int judSystemSecurity_1()
{
int i, j;
for (i = 0; i < resourseType; i++){
work[i] = available[i];
}
for (i = 0; i < customerNumber; i++){
if (isFinish(i)){
Finish[i] = 1;
}
else{
Finish[i] = 0;
}
}
int safeIndex = 0;
NEXT:
for (i = 0; i < customerNumber; i++){
if (Finish[i] == 0){
for (j = 0; j < resourseType; j++){
if (need[i][j] > work[j]){
break;
}
}
if (j == resourseType){
Finish[i] = 1;
SafeInfo(work, i);
safeSeries[safeIndex++] = i;
for (j = 0; j < resourseType; j++){//回收资源
work[j] += allocation[i][j];
}
goto NEXT;
}
}
}
int pNum = 0;
for (i = 0; i < customerNumber; i++){
if (Finish[i] == 0){
return 0;
}
else{
pNum++;
}
}
printf("\n安全序列为:");//打印安全序列
for (i = 0; i < customerNumber; i++){
if (isFinish(i)){//统计没完全执行的进程数
pNum--;
}
}
for (i = 0; i < pNum; i++){
printf("%d ", safeSeries[i]);
}
return 1;
}
//判断系统的安全性
int judSystemSecurity()
{
int i;
for (i = 0; i < resourseType; i++){//更新系统可利用资源量
work[i] = available[i];
}
int allFinish = 0;
//把未完成进程置为0
for (i = 0; i < customerNumber; i++){
//如果已经全部完成
if (isFinish(i)){
Finish[i] = 1;
allFinish++;
}
else{
Finish[i] = 0;
}
}
int r = 0;//表示当前要判断是否要进行预分配的进程的下标
int safeIndex = 0;//安全序列的下标
int temp = 0;//临时变量
int pNum = 0;//保存临时变量的个数
while (allFinish != customerNumber){
//预分配开始,当进程没有全部完成时,一直执行循环
num = 0;
for (i = 0; i < resourseType; i++){//判断是否可以预分配
if (need[r][i] <= work[i] && Finish[r] == 0){
num++;
}
}
//可以预分配
if (num == resourseType){
SafeInfo(work, r);//输出进程Pr的各项信息
for (i = 0; i < resourseType; i++){
work[i] = work[i] + allocation[r][i];
}//回收资源
allFinish++;//完成的进程数增加
safeSeries[safeIndex] = r;//保存安全序列
safeIndex++;
Finish[r] = 1;//当前进程安全
}
r++;//该式必须在此处
if (r >= customerNumber){
r = r % customerNumber;
if (temp == allFinish){
//temp记录的是上一次循环分配后所有的进程完成数,将上一次进程数跟这次预分配后的进程
//进行对比,如果相等,则是不安全的情况,直接break;否则是安全的情况,继续执行
break;
}
temp = allFinish;//更新完成的进程数
}
pNum = allFinish;//保存安全序列的个数
}
//判断系统是否安全
for (i = 0; i < customerNumber; i++){
if (Finish[i] == 0){
return 0;
}
}
//打印安全序列
printf("\n安全序列为:");
for (i = 0; i < customerNumber; i++){
if (isFinish(i)){
pNum--;
}
}
for (i = 0; i < pNum; i++){
printf("%d ", safeSeries[i]);
}
return 1;
}
//判断进程资源请求的安全性
void judRequestSecurity()
{
//输入预分配的资源编号和各类资源量
int curProcess;
printf("请输入预分配资源的进程的编号:");
scanf("%d", &curProcess);
getchar();
int i;
for (i = 0; i < resourseType; i++){
printf("请输入给 P%d 预分配的第 %d 类资源量:", curProcess, i + 1);
scanf("%d", &request[i]);
getchar();
}
//作为安全性的判断变量
num = 0;
//进行判断预分配是否合理
for (i = 0; i < resourseType; i++){
if (request[i] > need[curProcess][i]){
printf("\n分配错误!请求分配资源量大于所需要的资源量!\n");
printf("\nRESOURCE INSECURITY!!!\n\n
CUSTOMER P%d CAN NOT OBTAIN RESOURCES IMMEDIATELY\n\n", curProcess);
return;
}
else if (request[i] > available[i]){
printf("\n分配错误!请求分配资源量大于可利用资源量!\n");
printf("\nRESOURCE INSECURITY!!!\n\n
CUSTOMER P%d CAN NOT OBTAIN RESOURCES IMMEDIATELY\n\n", curProcess);
return;
}
else{
num++;
}
}
//分配合理,则试探性地分配
if (num == resourseType){
num = 0;
for (i = 0; i < resourseType; i++){
available[i] -= request[i];
allocation[curProcess][i] += request[i];
need[curProcess][i] -= request[i];
if (need[curProcess][i] == 0){
num++;
}
}
//分配合理并且此次分配后该进程执行结束,回收资源
if (num == resourseType){
for (i = 0; i < resourseType; i++){
available[i] += allocation[curProcess][i];
}
printf("\n进程 P%d 执行完毕,所占用资源全部释放!\n", curProcess);
}
else{
printf("\n进程 P%d 未执行完毕,等待\n", curProcess);
}
}
//检查分配后系统是否安全,如果不安全,则收回分配的资源
printf("\n--------------------------------------------
----------------------------------------\n");
printf("当前系统各类资源剩余量:");
for (int i = 0; i < resourseType; i++){
printf("%d ", available[i]);
}
printf("\n\n当前系统进程状况:\n");
printf(" Name\t Work\t Need\tAllocation\tWork+Allocation\t Finish\n");
if (!judSystemSecurity_1()){
for (i = 0; i < resourseType; i++){
available[i] += request[i];
allocation[curProcess][i] -= request[i];
need[curProcess][i] += request[i];
}
printf("\n\nRESOURCE INSECURITY!!!\n\n
CUSTOMER P%d CAN NOT OBTAIN RESOURCES IMMEDIATELY", curProcess);
}
else{
printf("\n\nRESOURCE SECURITY!!!\n\n
CUSTOMER P%d CAN OBTAIN RESOURCES IMMEDIATELY", curProcess);
}
printf("\n----------------------------------------------
--------------------------------------\n");
return;
}
6 实验结果
7 实验总结
为实现银行家算法,每个新进程在进入系统时它必须申明在运行过程中,可能需要的每种资源类型的最大单元数目,其数目不应超过系统所拥有的资源总量。当某一进程请求时,系统会自动判断请求量是否小于进程最大所需,同时判断请求量是否小于当前系统资源剩余量。若两项均满足,则系统试分配资源并执行安全性检查算法。