一、实验目的
了解掌握银行家算法,学会模拟实现资源分配,同时有要求编写和调试一个系统分配资源的简单模拟程序,观察死锁产生的条件,并使用适当的算法,有效的防止和避免死锁的发生
二、实验环境
VS2017+PC
三、实验内容
1.设计进程对各类资源最大申请表示及初值的确定。
2.设定系统提供资源的初始状况。
3.设定每次某个进程对各类资源的申请表示。
4.编制程序,依据银行家算法,决定其资源申请是否得到满足。
5.显示资源申请和分配时的变化情况。
四、实验步骤
1、初始化
由用户输入数据,分别对可利用资源向量矩阵AVAILABLE、最大需求矩阵MAX、分配矩阵ALLOCATION、需求矩阵NEED赋值。
2、银行家算法
在避免死锁的方法中,所施加的限制条件较弱,有可能获得令人满意的系统
性能。在该方法中把系统的状态分为安全状态和不安全状态,只要能使系统始终
都处于安全状态,便可以避免发生死锁。银行家算法的基本思想是分配资源之前,
判断系统是否是安全的;若是,才分配。设进程cusneed提出请求REQUEST [i],则银行家算法按如下规则进行判断。
(1)如果REQUEST [cusneed] [i]<= NEED[cusneed][i],则转(2)﹔否则,出错。
(2)如果REQUEST [cusneed] [i]<= AVAILABLE[cusneed][i],则转(3);否则,出错。
(3)系统试探分配资源,修改相关数据:AVAILABLE[i]-=REQUEST[cusneed][i];
ALLOCATION[eusneed][i]+=REQUEST[cusneed][i];NEED[cusneed][i]-=REQUEST[cusneed][i];
(4)系统执行安全性检查,如安全,则分配成立;否则试探险性分配作废,系统恢复原状,进程等待。
(5)对于某一进程i,若对所有的j,有NEED[i][i]=0,则表此进程资源分配完
毕,应将占用资源释放。
3、安全性检查算法
(1)设置两个工作向量Work=AVAILABLE;FINISH2)从进程集合中找到一个满足下述条件的进程,
FINISH==false ;
NEED<=Work;
如找到,执行(3);否则,执行(4)
(3)设进程获得资源,可顺利执行,直至完成,从而释放资源。
Work+=ALLOCATION;
Finish=true;
GOTO 2
(4)如所有的进程Finish= true,则表示安全;否则系统不安全。
五、总结
本次实验让我对银行家算法和死锁都有了一定的理解。知道了在资源一定的条件下为了让多个进程都能使用资源完成任务,避免死锁的产生可以从一开始就对系统进行安全性检查来判断是否将资源分配给正在请求的进程。但是银行家算法会加大系统的开销。
六、代码
// Test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
using namespace std;
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 12, M = 12; //最大进程数,最大资源种类
int n, m; //n个进程,m种资源
int mks[N][M]; //Max最大需求矩阵,进程i需要j类资源的数目
int alcs[N][M]; //Allocation分配矩阵,进程i的j类资源已分配的数目
int need[N][M]; //Need需求矩阵,进程i,j类资源还需要的数目
int avlb[M]; //Available可用资源向量,j类资源可用的数目
int sod[N]; //SafeOrder安全序列
int bkup_alcs1[N][M], bkup_need1[N][M], bkup_avlb1[M]; //BackUp备份
int bkup_alcs2[N][M], bkup_need2[N][M], bkup_avlb2[M]; //BackUp备份
void myinput() {
//输入
cout << "请输入每个进程的最大需求矩阵 分配矩阵 需求矩阵" << endl;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++)
cin >> mks[i][j];
for (int j = 0; j < m; j++)
cin >> alcs[i][j];
for (int j = 0; j < m; j++)
cin >> need[i][j];
}
cout << "请输入分配矩阵:" << endl;
for (int j = 0; j < m; j++)
cin >> avlb[j];
}
void myoutput() {
cout << "\n资源分配表\n\n";
cout << "进程\\资源\t最大需求矩阵\t分配矩阵\t需求矩阵" << endl;
for (int i = 0; i < n; i++) {
cout << "P" << i << "\t\t";
for (int j = 0; j < m; j++)
cout << mks[i][j] << " ";
cout << "\t\t";
for (int j = 0; j < m; j++)
cout << alcs[i][j] << " ";
cout << "\t\t";
for (int j = 0; j < m; j++)
cout << need[i][j] << " ";
cout << endl;
}
cout << "Available" << endl;
for (int j = 0; j < m; j++)
cout << avlb[j] << " ";
cout << endl;
}
//备份alcs,need,avlb
void backup(int bkup_alcs[N][M], int bkup_need[N][M], int bkup_avlb[M]) {
memcpy(bkup_alcs, alcs, sizeof alcs);
memcpy(bkup_need, need, sizeof need);
memcpy(bkup_avlb, avlb, sizeof avlb);
}
//恢复alcs,need,avlb
void recovery(int bkup_alcs[N][M], int bkup_need[N][M], int bkup_avlb[M]) {
memcpy(alcs, bkup_alcs, sizeof alcs);
memcpy(need, bkup_need, sizeof need);
memcpy(avlb, bkup_avlb, sizeof avlb);
}
//安全性检查
bool check_safe() {
backup(bkup_alcs1, bkup_need1, bkup_avlb1); //备份alcs,need,avlb
bool flag[N]; //已完成的进程的标志
int cnt = 0; //完成的进程数
//初始化falg
memset(flag, 0, sizeof flag);
//run
while (1) {
//遍历,找到可以满足的资源
int i;
for (i = 0; i < n; i++)
{
if (flag[i]) continue; //已完成的进程跳过
int j;
for (j = 0; j < m; j++)
if (need[i][j] > avlb[j])
break; //有资源不能满足,判断下个进程
if (j == m)
break; //找到了一个可以满足的进程,跳出
}
//如果找不到可以满足的进程,那么不是安全状态
if (i == n)
{
recovery(bkup_alcs1, bkup_need1, bkup_avlb1); //恢复alcs,need,avlb
return false;
}
int id = i; //取得进程编号
//回收该进程的资源
for (int j = 0; j < m; j++)
avlb[j] += alcs[id][j];
flag[id] = true; //当前进程设完成
sod[cnt] = id; //放安全序列
cnt++; //已完成++
if (cnt == n)
{
recovery(bkup_alcs1, bkup_need1, bkup_avlb1); //恢复alcs,need,avlb
return true; //全部完成,返回是安全状态
}
}
}
int request_resource(int id, int req[M]) {
//超需求判断
for (int j = 0; j < m; j++)
if (req[j] > need[id][j])
return 1;
//超可分配资源判断
for (int j = 0; j < m; j++)
if (req[j] > avlb[j])
return 2;
//假定分配
backup(bkup_alcs2, bkup_need2, bkup_avlb2); //备份alcs,need,avlb
for (int j = 0; j < m; j++)
avlb[j] -= req[j];
for (int j = 0; j < m; j++)
alcs[id][j] += req[j];
for (int j = 0; j < m; j++)
need[id][j] -= req[j];
//安全性检查
if (!check_safe()) {
recovery(bkup_alcs2, bkup_need2, bkup_avlb2); //恢复
return 3;
}
//检查通过,正式分配资源,也就不需要恢复备份了
return 0;
}
int main() {
cout << "请输入进程数 资源数" << endl;
cin >> n >> m;
myinput(); //输入参数
myoutput(); //输出表格
if (check_safe()) {
cout << "是安全状态,安全序列为" << endl;
for (int i = 0; i < n; i++)
{
cout << sod[i];
if (i != n - 1)
cout << "->";
}
cout << endl;
}
else
cout << "不是安全状态" << endl;
//输入请求资源
while (1) {
int id, req[M];
cout << "\n请输入要分配的进程 要分配的资源数量" << endl;
cin >> id;
if (id == 9999)
break;
for (int j = 0; j < m; j++)
cin >> req[j];
//做银行家算法分配资源的四个步骤
int res = request_resource(id, req);
switch (res)
{
case 0:
cout << "分配成功" << endl;
myoutput();
break;
case 1:
cout << "分配失败!请求的资源数超过最大值!" << endl;
break;
case 2:
cout << "分配失败!系统中尚无足够的资源满足P" << id<< "的申请!" << endl;
break;
case 3:
cout << "分配失败!假定分配后,无法通过安全性检查!"<< endl;
break;
}
}
return 0;
}
// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单
// 入门使用技巧:
// 1. 使用解决方案资源管理器窗口添加/管理文件
// 2. 使用团队资源管理器窗口连接到源代码管理
// 3. 使用输出窗口查看生成输出和其他消息
// 4. 使用错误列表窗口查看错误
// 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
// 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件