OS_死锁_银行家算法和安全性测试算法:C++实现

一、实验目的:
通过对银行家算法的模拟加深对避免死锁的理解,掌握银行家算法和安全性测试算法;
二、实验内容:
系统中有m个同类资源,被n个进程共享,每个进程对资源的最大需求数分别为S1、S2、…、Sn,且Max(Si)<=m(i=1,2,…,n)。进程可以动态地申请资源和释放资源。编写一个程序,实现银行家算法模拟分配资源以及进行安全性检测。当系统将资源分配给某一进程而不会死锁时,就分配之。否则,推迟分配,并显示适当信息。
三、实验要求:

  1. 将本实验分成两个阶段,第一阶段实现系统安全性检测算法(在系统安全的情况下要求输出安全序列), 第二阶段实现银行家算法。
  2. 要求用户能自主地输入不同的向量矩阵。
  3. 程序能正确输出不同的运算结果。
  4. 程序应具备良好的容错能力。

首先是头文件和预处理

#include<iostream>
#include<fstream>

#define pnum 5
#define rnum 3

pnum是processnum也就是进程数量,rnum是resourcenum也就是资源数量,这是一个关于如何合理的分配资源给进程的算法,在操作系统书上有讲解,希望读者区看看。


//定义安全性算法的数据结构
int sign[pnum],//安全序列
    work[pnum][rnum],//记录要显示的work,由算法种的work赋值得到,方便打印输出
	workAll[pnum][rnum];//work+allocation

//定义银行家算法的数据结构
int Available[pnum],//可用资源向量available
	Max[pnum][rnum],//最大需求向量,每个进程的最大需求
	Allocation[pnum][rnum],//分配矩阵,相当于当前已经分配了
	Need[pnum][rnum];//max-allocation,当前还需资源数目向量

根据书上的内容可以作出如下的定义,银行家算法的可用资源,最大等(有批注),安全性算法的work是为了显示,后面的算法中会有体现,work+allocation是根书上保持一致所以这样的一个定义,具体的可以根据书上的表格进行比较,话不多说,老规矩,main函数分析。

首先在main函数中我们是需要申请多少的资源,是哪个进程申请,所以我们需要定义个request二维数组,进行一个资源的申请,行为进程pnum列为资源rnum
这时候,看了我前面的应该知道,我们需要进行一个创建,我们最大资源是多少,有多少个进程什么什么的,这些可以根据书上的已知条件,从而知道我们有多少数据需要用户进行一个输入。

creat函数进行一个封装,初始化

基本思想:将max,allocation,need,available数组装载数值,有些是一维,有些是二维,根据书上的已知条件可以得到如何创建,这里可能有些读者没书,在此给出代码

//初始化
void creat(){
	for(int i = 0;i<pnum;i++){
		cout<<"请输入第 "<<i<<" 个进程的数据:"<<endl;
		cout<<"MAX:第"<<i<<"个进程一共需要申请多少个资源(A B C):";
			for(int j=0;j<rnum;j++)
				cin>>Max[i][j];
			cout<<"Allocation:已获得的资源数量(A B C):  ";
			for(int j=0;j<rnum;j++)
				cin>>Allocation[i][j];
			cout<<"Need:还需要的资源数量(A B C):  ";
			for(int j=0;j<rnum;j++)
				cin>>Need[i][j];

			if(i==0){
				cout<<"Available:现有资源的数量(A B C):  ";
                for(int j = 0;j < rnum;j++)
                        cin>>Available[j];
			}
	}
}

这时候我们回到我们的main,创建好了之后我们需要输入request数组中是哪个进程申请资源数量为多少,为了让读者阅读方便,在此也给出代码

while(true){
		cout<<endl<<"请输入Request[进程标号i][资源类型j]:"<<endl;
        cout<<"进程i=:";
        cin>>i;
        cout<<"各类资源数量(A B C):  ";
            for(int j = 0;j < rnum;j++)
                cin>>Request[i][j];
            cout<<endl;
        //执行银行家算法
            int res = Banker(i,Request);
        //输出每次判断产生的执行序列
            cout<<endl<<"当前的资源分配表:"<<endl;
            show(res);
	}

你会发现有banker里面的参数是进程几申请资源,最终返回的结果用来输出,那么我们的show应该如何的进行定义呢?
我们得显示我们的资源分配表,如果说安全性算法后还有一个安全队列,我们得输出安全性队列下的work等一系列,如果没有,我们就输出我们各个进程初始信息,all+need+available。让用户明白自己的申请的问题出错在哪。

show:资源分配表的定义

首先show函数得接收一个值,res,表示有无安全序列,如果有,就是我的进程数,如果没有,就是不能构成安全序列我们需要输出它的初始信息
这里直接给源码,希望读者读懂后可以评论区留言说说你的理解

void show(int res){
	if(res == pnum){
		cout<<" 进程号--"<<" Work[A,B,C]"
		<<" Need[A,B,C]"<<" Allocation[A,B,C]"<<" Work+Allocation[A,B,C]"<<" Finish"<<endl;
        for(int i = 0;i < pnum;i++) {
            for(int j = 0;j < rnum;j++)
                cout<<work[sign[i]][j]<<" ";
            cout<<'	'<<'	';
            for(int j = 0;j < rnum;j++)
                cout<<Need[sign[i]][j]<<" ";
            cout<<'	'<<'	';
            for(int j = 0;j < rnum;j++)
                cout<<Allocation[sign[i]][j]<<" ";
            cout<<'	'<<'	';
            for(int j = 0;j < rnum;j++)
                cout<<workAll[sign[i]][j]<<" ";
            cout<<'	'<<'	';
            cout<<"true"<<endl;
        }
	cout<<endl<<"安全序列为:{p["<<sign[0]<<"]";
	for(int m = 1;m<pnum;m++){
		cout<<",p["<<sign[m]<<"]";
	}
	cout<<"}"<<endl;
}
	else{//没通过输出信息
		cout<<" 进程号--"<<" Allocation[A,B,C]"
			<<" Need[A,B,C]"<<" Available[A,B,C]"<<endl;
		for(int k = 0;k < 5;k++){
			cout<<'	'<<"P["<<k<<"]"<<'	'<<'	';
			for(int j = 0;j < 3;j++)cout<<Allocation[k][j]<<" ";
			cout<<'	'<<'	';
			for(int j = 0;j < 3;j++)cout<<Need[k][j]<<" ";
			cout<<'	'<<'	';
			if(k == 0) {
				for(int j = 0;j < 3;j++)
				cout<<Available[j]<<" ";
			}
			cout<<endl;
		}
	}
}

现在进入正题

银行家算法banker(i,request[][rnum])

基本思想:第一步,//判断request内的资源是否比可用总数和进程i总共所需的大小,这是基本的条件
如何的实现呢?

for(int j = 0;j < rnum;j++) {
        if(Request[i][j] > Need[i][j]){
            cout<<"分配失败------>"<<endl<<"所需资源数超出其宣布的最大值!"<<endl;
            return 0;
        } else if(Request[i][j] > Available[j]) {
                    cout<<"分配失败------>"<<endl<<"无足够资源,p["<<i<<"]需要进行wait"<<endl;
                    return 0;
                }
        }

如果通过了,我们试着分配资源,进行安全性算法,如果没通过就直接返回了error,也会输出提示信息。

尝试分配资源我们应该怎么做呢?

首先让资源总数available减去request,让进程的allocation加上申请的,need也需要减去request。
大致理解:因为你申请了资源现在在假定分配,所以分配给你了系统的可用资源就要减少,当前进程的已用资源就要增加,目前还需资源就也要减少,因为系统已经满足你的需求了。

        for(int j = 0;j < rnum;j++) {
                Available[j] = Available[j] - Request[i][j];
                Allocation[i][j] = Allocation[i][j] + Request[i][j];
                Need[i][j] = Need[i][j] - Request[i][j];
        }

执行安全性算法,根据安全性算法的返回值,确定是否有队列,最终输出显示的情况
后续代码我只给出执行安全性算法,如何让系统交互做的更好留给读者。


        int n = Safe(Available,Need,Allocation);
        cout<<endl;

        if(n == pnum) {//有5个'true'返回1,表示此时刻安全

接下来来到安全性算法safe,它带了参数available和need和allocation

我们为了方便运算,原来的work为了存放available总数加上释放,所以我们这里新建一个work数组,它是一维的,因为它只需要将一组的数据进行一个传递,finish数组的定义为了判断是否有一个队列,所以它的大小为pnum。这里给出定义,ijmn是根据我的需求进行一个添加

int Safe(int Available[],int Need[][rnum],int Allocation[][rnum]) {
	int i=0,j=0,m=0,n=0;
	int Work[rnum],Finish[pnum] = {0,0,0,0,0};

接下来我们将我们的可用资源数目给我们的work临时一维数组。

进入一个大while,只要我们的i<进程总数pnum我们就继续在循环中找。这里你应该明白i是为了计数,看看有无这么多的进程完成,如果实在没有我们的扫描也会结束,到时候finish和i的值都不是理想值

只要对应的finish[i]是等于0 的说明还没有被加入就绪队列,首先判断现有的资源总量能否满足它的需求,可以满足我们就进行一个分配。这里分配后直接释放了,所以我们可以直接让work加上allocation中当前i进程的已用资源allocation,在这之前用我们的work二维数组记录下我们当前的work再去加进行一个变化,这样在循环中,work中就是显示未释放的状态中的可用资源,让我们的workall等于我们的一维数组work,有些许绕,我附上小部分的代码,希望读者钻研一下。

if(j == rnum){//如果need的三个资源都可以被满足,就分配并且释放和记录
				 for(int k = 0;k < rnum;k++){
                    work[i][k] = Work[k];//记录分配前的可用的资源总数
                    Work[k] = Work[k]+Allocation[i][k];
					workAll[i][k] = Work[k];
				}

如果我们这一步成功了,说明是可以分配的,让我们的安全序列数组sign中的第一个m变成i。finish[i]=1,i=-1,m++.
i 等于-1是因为在我们的if(Finish[i]==0){后还有一段代码,我们慢慢分析

我们是从头开始扫描,所以如果没加入,或者已经加入过了我们必须让我们的i++,让我们的j(用于检查可用资源是否满足的一个变量)归零。所以在if中我们的i=-1,在外++就变成了0,就是继续从首部查找。

最终根据finish中是否有0,我们可以得到我们是该返回pnum还是其他数字了。

到此已经讲述完了,希望读者能够仔细思考一下问题,后续结果有人提问我再在评论区更新!!!

原文地址:https://www.cnblogs.com/hgao/p/13166804.html