• 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还是其他数字了。

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

  • 相关阅读:
    C++拷贝构造函数(深拷贝,浅拷贝)
    c++ string assign =
    undefined与null的区别---js
    Cocos2d-x内存自动释放机制--透彻篇
    cocos2d-x 坐标系
    cocos-html5 JS 写法基础 语言核心
    selenium--更改标签的属性值
    selenium--高亮显示正在操作的元素
    selenium--页面元素是否可见和可操作
    selenium--拖拽页面元素
  • 原文地址:https://www.cnblogs.com/hgao/p/13166804.html
Copyright © 2020-2023  润新知