广州大学学生实验报告
开课学院及实验室:计算机科学与网络工程学院 软件实验室 2023年5月19日
学院 | 计算机科学与网络工程学院 | 年级/专业/班 |
| 姓名 |
| 学号 | |
实验课程名称 | 操作系统实验 | 成绩 | |||||
实验项目名称 | 银行家算法 | 指导老师 |
实验二 银行家算法
一、实验目的
1、了解什么是操作系统安全状态和不安全状态;
2、了解如何避免系统死锁;
3、理解银行家算法是一种最有代表性的避免死锁的算法,掌握其实现原理及实现过程。
二、实验环境
Visual Studio 2019
三、实验内容
根据银行家算法的基本思想,编写和调试一个实现动态资源分配的模拟程序,并能够有效避免死锁的发生。
四、实验原理,实验中用到的系统调用函数(包括实验原理中介绍的和自己采用的),实验步骤
1、实验原理:
①什么是系统的安全状态和不安全状态
所谓安全状态,是指如果系统中存在某种进程序列<P1,P2,…,Pn>,系统按该序列为每个进程分配其所需要的资源,直至最大需求,则最终能使每个进程都可顺利完成,称该进程序列<P1,P2,…,Pn,>为安全序列。
如果不存在这样的安全序列,则称系统处于不安全状态。
②银行家算法
把操作系统看作是银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求分配资源相当于用户向银行家贷款。
为保证资金的安全,银行家规定:
当一个顾客对资金的最大需求量不超过银行家现有的资金时就可接纳该顾客;
顾客可以分期贷款,但贷款的总数不能超过最大需求量;
当银行家现有的资金不能满足顾客尚需的贷款数额时,对顾客的贷款可推迟支付,但总能使顾客在有限的时间里得到贷款;
当顾客得到所需的全部资金后,一定能在有限的时间里归还所有的资金。
③按照银行家制定的规则设计的银行家算法
进程首次申请资源的分配:如果系统现存资源可以满足该进程的最大需求量,则按当前的申请量分配资源,否则推迟分配。
进程在执行中继续申请资源的分配:若该进程已占用的资源与本次申请的资源之和不超过对资源的最大需求量,且现存资源能满足该进程尚需的最大资源量,则按当前申请量分配资源,否则推迟分配。
至少一个进程能完成:在任何时刻保证至少有一个进程能得到所需的全部资源而执行到结束。
2、实验中用到的系统调用函数
因为是模拟程序,可以不使用系统调用函数。
3、银行家算法流程图
4、数据结构说明
int M; //系统资源类数
int N; //系统进程数
int** max = NULL; //N个进程对M类资源最大资源需求量
int* available = NULL; //系统可用资源数
int** allocation = NULL; //M个进程已分配的资源量
int** need = NULL; //M个进程还需要的资源数量
int* tatalResource = NULL; //系统每类资源的总数量
int* safety = NULL; //用来记录进程安全执行的顺序
int work[100]; //表示系统可提供给进程的各类资源数目
int* finish = NULL; //表示系统是否有足够的资源分配给进程
说明:
用一个N*M的矩阵max表示每个进程对资源的最大需求
长度为M的向量available表示每类资源的当前可用数量
用一个N*M的矩阵allocation表示当前M个进程所占有的资源数目
用一个N*M的矩阵need表示M个进程分别需要的资源数目
向量totalReasource表示每类资源的总数量
长度为M的向量work表示系统可提供给进程的各类资源数目
长度为N的向量finish, 表示系统是否有足够的资源分配给进程。有为true,否则为false。
五、实验结果分析(截屏的实验结果,与实验结果对应的实验分析)
(一)实验结果与实验程序、实验步骤、实验原理、操作系统原理的对应分析;
(二)不同条件下的实验结果反应的问题及原因;
(三)实验结果的算法时间、效率、鲁棒性等性能分析。
1、安全的情况
案例1
案例2
案例3
2、不安全的情况
案例1
案例2
案例3
结果分析:银行家算法是需要进程的最大需求量是要小于系统每类资源的的数量,而且系统分配的资源是不能超过进程的最大需求量,当一个进程结束之后释放资源后,系统的可用资源不足以满足下一个进程的运行的时候,系统就会不分配资源,避免造成死锁。
所以设计程序的时候要考虑将系统总资源尽量大于进程所需的资源数量,即设置系统每类总资源量是5到9,进程最大需求量是0到6,这样就大概率系统可以处于安全状态。
当进程的最大需求量较大,系统每类资源数量较少的时候,系统就会容易处于一个不安全的状态,设计的时候为了显示两种情况,将系统资源数量和进程所需资源量进行平衡,由结果得到,系统各类资源的数量越多,进程需要的资源类越少,系统更容易得到安全序列,这样也就表示系统的资源量提高,有利于提高系统的安全性。
六、实验总结
(一) 实验思考题的回答
1、如何设计程序的输入模块才能满足实验要求,请举例说明;
首先实验要求数据随机产生,所以需要在初始化保证进程的最大需求量要小于系统每个资源的数量,并且系统分配的资源不能大于进程的需求量,进程需要的资源等于进程所需要的最大需求量减去已经分配给进程的资源。例如,need=MAX-Allocation。
除此之外,系统的分配资源为系统全部资源数减去已经分配给进程的数量,例如,Available=Total_Rescource-Allocation,同时实验要求最后需要一个进程包含系统的所有资源才结束,在实验开始的时候就需要判断进程的数量。
2、银行家算法在实现过程中必须注意哪些资源分配细节才能避免死锁?
需要比较系统每类资源数量和进程需要最大资源类,进程需要的资源量必须不超过系统可分配的资源量,如果超过了就必须退出去,系统再和下一个进程匹配,不满足请求的进程返回系统分配资源,直到全部进程匹配完毕,需要让系统得到一个安全序列,系统给每个进程分配资源达到最大资源,让每个进程都能顺利完成,来避免死锁。
(二)个人总结
本次实验主要学习了银行家算法的理论和银行家算法代码实现、系统的安全和不安全状态、系统为什么会进入死锁和避免死锁的状态以及银行家算法是如何避免死锁的。
在基本掌握了银行家算法的实现原理后,我在本次实验入手阶段还是比较艰难,但在搜集网络资源、与同学讨论过后,我又对银行家算法有了更深入的了解。
本实验中的进程数和进程最大需求量以及系统总资源的设置需要在合理的范围之内,不然容易导致系统长期处于一种状态。
七、实验数据及源代码(学生必须提交自己设计的程序源代码,并有注释,源代码电子版也一并提交),包括思考题的程序。
注意: 实验报告文件名 学号-姓名-实验1-班级
实验数据与源代码 一个压缩包,名字和实验报告规则一样,需要有一个说明文件解释各个文件是什么文件。
代码源程序:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define false 0
#define true 1
int M; //系统资源类数
int N; //系统进程数
int** max = NULL; //N个进程对M类资源最大资源需求量
int* available = NULL; //系统可用资源数
int** allocation = NULL; //M个进程已分配的资源量
int** need = NULL; //M个进程还需要的资源数量
int* tatalResource = NULL; //系统每类资源的总数量
int* safety = NULL; //用来记录进程安全执行的顺序
//初始化进程和资源
void Init()
{
srand((unsigned int)time(NULL)); //随机数种子
int i, j;
int test = 1;
int test2 = 0;
M = rand() % 4 + 4; //随机生成系统资源类数
N = rand() % 4 + 3; //随机进程数
while (test == 1)
{
tatalResource = (int*)malloc(sizeof(int) * M); //为各个数组分配内存
available = (int*)malloc(sizeof(int) * M);
max = (int**)malloc(sizeof(int*) * N);
allocation = (int**)malloc(sizeof(int*) * N);
need = (int**)malloc(sizeof(int*) * N);
for (i = 0; i < N; i++)
{
max[i] = (int*)malloc(sizeof(int) * M);
allocation[i] = (int*)malloc(sizeof(int) * M);
need[i] = (int*)malloc(sizeof(int) * M);
}
for (i = 0; i < M; i++)
{
tatalResource[i] = rand() % 5 + 5; //随机生成每类资源的总数量
available[i] = tatalResource[i];
}
for (i = 0; i < N; i++)
{
for (j = 0; j < M; j++)
{
int safety = 0;
while (1)
{
safety = rand() % 6;//随机生成最大资源需求量
if (safety <= tatalResource[j])
break;
}
max[i][j] = safety;
int temp2 = 0;
while (1)
{
temp2 = rand() % 4;
if (temp2 <= max[i][j]) //随机生成已分配资源数,并且要求分配量要小于最大资源需求量
break;
}
allocation[i][j] = temp2;
need[i][j] = max[i][j] - allocation[i][j];
}
}
for (i = 0; i < M; i++)
{
for (j = 0; j < N; j++)
{
available[i] -= allocation[j][i]; //计算出分配资源后系统可用资源量
}
}
for (i = 0; i < N; i++)//保证至少一个进程能够得到全部所需资源而结束
{
test2 = 1;
for (j = 0; j < M; j++)
{
if (available[j] < need[i][j])
{
test2 = 0;
break; //对于某个进程,任意一种可用资源少于所需资源时,置0
}
}
if (test2 == 1)//所有可用资源都满足某个进程运行
{
test = 0;
break;
}
}
}
printf("----------------------------------随机生成测试数据----------------------------------\n");
printf("系统的进程数为:%d\n", N);
printf("系统的资源类数为:%d\n", M);
printf("系统中每类资源的总数量依次为:");
for (i = 0; i < M; i++)
{
printf("%d ", tatalResource[i]);
}
printf("\n");
printf("--------------------------------T0时刻资源分配状态表--------------------------------\n");
printf(" Allocation\tMax\t\tNeed\t\tAvailable\n");
for (i = 0; i < N; i++)
{
printf("进程%d\t", i + 1);
for (j = 0; j < M; j++)
{
printf("%d ", allocation[i][j]);
}
printf("\t");
for (j = 0; j < M; j++)
{
printf("%d ", max[i][j]);
}
printf("\t");
for (j = 0; j < M; j++)
{
printf("%d ", need[i][j]);
}
printf("\t");
if (i == N / 2)
{
for (j = 0; j < M; j++)
{
printf("%d ", available[j]);
}
}
printf("\n");
}
}
//安全性算法
int security(int pid)
{
safety = (int*)malloc(sizeof(int) * N);//进程安全执行的顺序
int work[100]; //表示系统可提供给进程的各类资源数目
int* finish = NULL;
finish = (int*)malloc(sizeof(int) * N); //表示系统是否有足够的资源分配给进程
int i, j, k;
int count = 0; //进程执行序号
for (i = 0; i < N; i++)
{
finish[i] = false;
}
for (i = 0; i < M; i++)
{
work[i] = available[i];
}
safety[count++] = pid;
finish[pid] = true; //设置为已执行
count = 1;
for (i = 0; i < M; i++) //回收资源
{
work[i] += allocation[pid][i];
}
//对剩下进程进行计算
while (1)
{
int test = 1;
int test2 = 1;
for (i = 0; i < N; i++)
{
for (k = 0; k < M; k++)
{
if (need[i][k] > work[k])
test = 0;
}
if ((finish[i] == false) && (test == 1))
{
for (j = 0; j < M; j++)
work[j] += allocation[i][j];
finish[i] = true;
safety[count++] = i; //记录执行顺序
test2 = 0; //置0
}
}
if (test2 == 1) //没有满足条件的进程,退出循环
break;
}
int index = 1;
for (i = 0; i < N; i++)
{
if (finish[i] == false) //如果存在进程不能执行,返回0
index = 0;
}
return index;
}
//银行家算法
void Bank()
{
int i, j, T;
int* Request = NULL;
Request = (int*)malloc(sizeof(int) * M);
int test = 1;
while (test == 1)
{
test = 0;
T = rand() % N; //随机选取一个进程
for (i = 0; i < M; i++)
{
Request[i] = need[T][i]; //定义进程申请资源量等于进程资源需求量
if (Request[i] > available[i])
test = 1;
//如果现有资源无法满足该进程需求,则选择另一个进程,继续检查
}
}
printf("----------------------------随机选取一个进程进行资源分配----------------------------\n");
printf("系统尝试把资源分配给进程%d\n", T + 1);
for (i = 0; i < M; i++) //分配资源
{
available[i] -= Request[i];
allocation[T][i] += Request[i];
need[T][i] -= Request[i];
}
int test2 = security(T); //调用安全算法
if (test2 == 0)
{
printf("由于分配资源不安全,所以系统恢复之前的状态,不进行分配,程序运行结束\n");
for (i = 0; i < M; i++) //回收资源
{
available[i] += Request[i];
allocation[T][i] -= Request[i];
need[T][i] += Request[i];
}
}
else //系统安全,输出安全序列
{
printf("系统分配的资源后安全,生成安全序列为:");
for (i = 0; i < N; i++)
{
printf("%d", safety[i] + 1);
}
printf("\n");
int* work = 0;
work = (int*)malloc(sizeof(int) * M);
for (i = 0; i < M; i++)
{
available[i] += Request[i];
allocation[T][i] -= Request[i];
need[T][i] += Request[i];
work[i] = available[i];
}
printf("------------------------------------安全情况分析------------------------------------\n");
printf(" Work\t\tNeed\t\tAllocation\tWork+Allocation\n");
for (i = 0; i < N; i++)
{
printf("进程%d\t", safety[i] + 1);
for (j = 0; j < M; j++)
{
printf("%d ", work[j]);
}
printf("\t");
for (j = 0; j < M; j++)
{
printf("%d ", need[i][j]);
}
printf("\t");
for (j = 0; j < M; j++)
{
printf("%d ", allocation[i][j]);
}
printf("\t");
for (j = 0; j < M; j++)
{
work[j] += allocation[i][j];
printf("%d ", work[j]);
}
printf("\n");
}
}
}
//释放资源
void Release()
{
free(available);
for (int i = 0; i < N; i++)
{
free(max[i]);
free(allocation[i]);
free(need[i]);
}
free(max);
free(allocation);
free(need);
}
//主程序
int main()
{
Init(); //初始化数据
Bank(); //调用银行家算法
Release();//释放资源
system("pause");
}