死锁的避免与检测(操作系统课设)

特别声明:本博客属于原创内容,若需转载或引用,请均注明转载和加上相应的链接信息!!!!

设计目的

操作系统课程设计的主要任务是研究计算机操作系统的基本原理和算法,掌握操作系统的进程管理、存储管理、文件管理和设备管理的基本原理与主要算法。本次课程设计掌握银行计算法,加深对避免死锁方法的理解,更清楚地理解资源的变化过程。通过编写可以基本上实现银行家算法所要达到的基本目的,在输入正确的情况下能够输出正确的安全序列,在不安全的情况下可以做出提醒,并且恢复原有输入数据。死锁检测算法能够演示资源分配图的简化过程,并给出最终检测结果(系统死锁还是不死锁)加深对死锁的判定过程的理解。

设计内容

用C或C++语言实现一个程序演示死锁避免算法(银行家算法)。要求该演示程序能显示各进程申请和释放资源以及系统动态分配资源的过程,便于用户观察和分析;允许进程动态地申请资源分配之前,应先计算此次资源分配的安全性。若此次分配不会导致系统进入不安全状态,则将资源分配给进程;否则,令进程等待。如果系统不能分配,也应给出“系统进入不安全状态”的提示。
用C或C++语言实现一个程序演示死锁检测算法。设计一个程序演示教材P116-117给出的死锁检测算法。要求该演示程序能显示资源分配图的简化过程,并给出最终检测结果(系统死锁还是不死锁)。

总体设计

死锁避免算法
在这里插入图片描述
死锁检测算法
在这里插入图片描述

开发环境

Windows 10系统,VC++6.0开发工具。

算法设计

安全性算法
在这里插入图片描述
根据随机输入的Allocation和Max矩阵来确定Need矩阵,通过循环遍历每个进程的Need矩阵与Available相比较,查看能否满足需求。若能,则修改Available,进行下一步,若不能,则对比下一个进程。

银行家算法
在这里插入图片描述
银行家算法要给定进程数和资源数,在随机输入符合要求的Allocation,Max,Need矩阵,给出Available向量,完成初始化。当有进程申请资源时要对比本身Need量以及可用Available量,满足后进行预分配,利用安全性算法进行检查。若结果为系统处于安全状态则正是为进程分配资源,否则驳回其请求。

死锁检测算法
该算法和安全性算法很类似,同样要给出Allocation,Max,Need矩阵,以及Available向量,同样要对每个进程进行Need与Available的比对,只是在比对后的操作略有不同,该算法要能够简化资源分配图,并给出结果。

系统实现

注:里面有部分代码参考过他人代码,但目前找不到相关引用链接,若有侵权部分,请联系我删掉!!!!

银行家算法
1 初始化模块实现

int Available[100]; //可利用资源数组
int Max[50][100];   //最大需求矩阵
int Allocation[50][100];  //分配矩阵
int Need[50][100];        //需求矩阵
int Request[50][100];     //M个进程还需要N类资源的资源量
int Finish[50];
int p[50];
int m,n;   //M个进程,N类资源
int i,j,mi;
    cout<<"输入进程的数目:\n";
    cin>>m;
    cout<<"输入资源的种类:\n";
    cin>>n;
    cout<<"输入每个进程最多所需的各类资源数,按照"<<m<<"x"<<n<<"矩阵输入\n";
    for (i=0;i<m;i++)        //给出Max矩阵
        for(j=0;j<n;j++)
            cin>>Max[i][j];
    cout<<"输入每个进程已经分配的各类资源数,按照"<<m<<"x"<<n<<"矩阵输入\n";
    for (i=0;i<m;i++)                //给出Allocation矩阵
    {
        for(j=0;j<n;j++)
        {
            cin>>Allocation[i][j];
            
        }
    }
	cout<<"Need矩阵为:\n";
	for (i=0;i<m;i++)                  //给出Need矩阵
        for(j=0;j<n;j++)
            cin>>Need[i][j];
		    if (Need[i][j]<0)
				cout<<"第"<<i<<"行第"<<j<<"个资源出错,请重输:\n";
				j--;
			
    cout<<"请输入各个资源现有的数目:\n";
    for (i=0;i<n;i++)                   //给出Available向量
    cin>>Available[i];

2 安全性算法模块实现

//安全性算法
int Safe()                      
{
    int i,j,l=0;
    int Work[100];//可利用资源数组
	int Need1[50][100];           //定义举证,实时显示各进程的Need量
	for(i=0;i<m;i++)
	{
		for(j=0;j<n;j++)
		{
			Need1[i][j]=Need[i][j];
		}
	}
    for (i=0;i<n;i++)
        Work[i]=Available[i];
    for (i=0;i<m;i++)
        Finish[i]=0;
    for (i=0;i<m;i++)
    {
        if (Finish[i]==1)
        continue;
        else
        {
            for (j=0;j<n;j++)
            {
                if (Need[i][j]>Work[j])
                    break;
            }
            if (j==n)
            {
                Finish[i]=1;
                for(int k=0;k<n;k++)          //与每个进程匹配,若满足,则将该进程拥有的资源收回,并修改相应矩阵
				{
					Work[k]+=Allocation[i][k];
				    Need1[i][k]=0;
				}
//动态显示资源分配过程
				cout<<"现在为P"<<i<<"分配资源"<<'\n';
				cout<<"满足后work矩阵为:"<<'\n';
				for(int a=0;a<n;a++)
				{
					cout<<Work[a]<<' ';
				}
				cout<<'\n';
				cout<<"满足后Need1矩阵为:"<<'\n';
				for(int c=0;c<m;c++)
				{
		             for(int b=0;b<n;b++)
					 {
						 cout<<Need1[c][b];
					 }
					 cout<<'\n';
				}

                p[l++]=i;
                i=-1;
            }
            else continue;
        }
        if (l==m)
        {
            cout<<"系统是安全的"<<'\n';
            cout<<"系统安全序列是:\n";
            for (i=0;i<l;i++)
            {
                cout<<p[i];
                if (i!=l-1)
                    cout<<"-->";
            }
            cout<<'\n';
            return 1;
        }
    }
}

3 请求资源模块实现

 while (1)
    {
        cout<<"输入要申请的资源的进程号:(第一个进程号为0,第二个进程号为1,依此类推)\n";
        cin>>mi;
        cout<<"输入进程所请求的各个资源的数量\n";
        for (i=0;i<n;i++)
        cin>>Request[mi][i];
        for (i=0;i<n;i++)
        {

            if (Request[mi][i]>Need[mi][i])
            {
                cout<<"所请求资源数超过进程的需求量!\n";
                return 0;
            }
            if (Request[mi][i]>Available[i])
            {
                cout<<"所请求资源数超过系统所有的资源数!\n";
                return 0;
            }
        }
        for (i=0;i<n;i++)
        {
            Available[i]-=Request[mi][i];
            Allocation[mi][i]+=Request[mi][i];
            Need[mi][i]-=Request[mi][i];
        }
        if (Safe())
            cout<<"同意分配请求\n";
        else
        {
            cout<<"SORRY╮(╯▽╰)╭……你的请求被拒绝…\n";
            for (i=0;i<n;i++)
            {
                Available[i]+=Request[mi][i];
                Allocation[mi][i]-=Request[mi][i];
                Need[mi][i]+=Request[mi][i];
            }
        }
        for (i=0;i<m;i++) 
            Finish[i]=0;
        char Flag;       //标志位
        cout<<"是否再次请求分配?是请按Y/y,否请按N/n";
        while (1)
        {
            cin>>Flag;
            if (Flag=='Y'||Flag=='y'||Flag=='N'||Flag=='n')
            break;
            else
            {
                cout<<"请按要求重新输入:\n";
                continue;
            }
        }
        if (Flag=='Y'||Flag=='y')
        continue;
        else break;
    }
}

4.2 死锁检测算法
1 初始化模块实现

vector<int> Allocation[500];   //每个进程已经有的资源
vector<int> Need[500];   //各个进程想要的资源
int pro_size;	//进程数
int res_size;	//资源种类数
int res[500];	//每类资源的个数
int work[500];	//当前可用资源数
vector<int> Deadlock;
bool* visited;
bool* Dead_res;
void read_data(){
	ifstream in;
	in.open("D:\\deadlock detection.txt");
	if(!in)
		cout << "FILE OPEN FAILED!" << endl;
	memset(res,0,500);
	memset(work,0,500);
//**********************************************
//Read res
	in >> res_size;
	if(res_size > 500){
		cout << "Number of res should be small than 500" << endl;
		exit(-1);
	}
	for(int i = 0; i < res_size; i++){
		int temp;   //每类资源的个数
		in >> temp;
		if(temp < 0){
			cout << "Illegal No. of res!" << endl;
			cout <<"Please check your input data!" << endl;
			exit(-1);
		}
		res[i] = work[i] = temp;
	}
//************************************************
//Read pro
	in >> pro_size;
	if(pro_size > 500){
		cout << "Number of pro should be small than 500" << endl;
		exit(-1);
	}
	for(int k = 0; k < pro_size; k++){

		int num;
		in>> num;
		int have_size;   //每个进程拥有的资源数
		in >> have_size;
		for(int i = 0; i < have_size; i++){
			int temp; 
			in >> temp;    //拥有资源的编号
			if(temp >= res_size){
				cout << "illegal res No.!" << endl;
				cout <<"Please check your input data!" << endl;
				exit(-1);
			}
			work[temp]--;
			if(work[temp] < 0){
				cout << "Impossible res dispatch situation!" << endl;
				cout <<"Please check your input data!" << endl;
				exit(-1);
			}
			Allocation[num].push_back(temp);
		}
//--------------------------------------------------------		
		int want_size;    //每个进程想要的资源数
		in >> want_size;
		for(int j = 0; j < want_size; j++){
			int temp;   //想要资源的编号
			in >> temp;
			if(temp >= res_size){
				cout << "illegal res No.!" << endl;
				cout <<"Please check your input data!" << endl;
				exit(-1);
			}
			Need[num].push_back(temp);
		}
	}
}

2 画图模块的实现
该程序要实时显示资源分配图的简化过程。对每一类资源画一个圈,这类资源的数目在圈中用小圆来表示,有几个资源就画几个小圆。对每一个进程,画一个矩形。然后根据每个进程的“占有”、“申请”状况,矩形和圈之间用绿线表示此进程拥有一个此类资源;用红线表示此进程申请一个此类资源。

void Draw(){
	HWND hWnd=FindWindow("ConsoleWindowClass",NULL);
	HDC hDc=GetDC(hWnd);
    HPEN hPen1=CreatePen(PS_SOLID,2,0x000000FF);//生成红线
	HPEN hPen2=CreatePen(PS_SOLID,2,0x0000FF00);//生成蓝线
	SelectObject(hDc,hPen1);

	int i;
	for( i = 0; i < res_size; i++){
		Ellipse(hDc,i*100,0,i*100+50,50);
		char s[5];
		s[0] = 'R';
		s[1] = i+48;
		s[2] = '\0';
		TextOut(hDc,i*100+20,25,s,2);
		for(int k = 0; k < res[i]; k++)
			Ellipse(hDc,i*100+k*10+5,10,i*100+k*10+15,20);
	}
	
	for(i = 0; i < pro_size; i++){
		Rectangle(hDc,i*100,100,i*100+50,150);
		char s[5];
		s[0] = 'P';
		s[1] = i+48;
		s[2] = '\0';
		TextOut(hDc,i*100+20,125,s,2);
	}
	for(i = 0; i < 10; i++)
		cout << endl;

	for(i = 0; i < pro_size; i++)
		for(int k = 0; k < res_size; k++){
			int cnt = 5;
			int j;
			for(j = 0; j < Allocation[i].size(); j++){
				if(Allocation[i][j] == k){
					SelectObject(hDc,hPen2);
					MoveToEx(hDc,i*100+cnt,100,NULL);
					LineTo(hDc,k*100+cnt,50);
					cnt += 10;
				}
			}
			
			cnt = 5;
			for(j = 0; j < Need[i].size(); j++){
				if(Need[i][j] == k){
					SelectObject(hDc,hPen1);
					MoveToEx(hDc,i*100+50+cnt,100,NULL);
					LineTo(hDc,k*100+cnt,50);
					cnt -= 10;
				}
			}
		}
}
//**********************************************************

void ers(int i){
	system("pause");
	HWND hWnd=FindWindow("ConsoleWindowClass",NULL);
    HDC hDc=GetDC(hWnd);
    HPEN hPen=CreatePen(PS_SOLID,2,0x00000000);
	SelectObject(hDc,hPen);

	for(int k = 0; k < res_size; k++){
			int cnt = 5;
			int j;
			for(j = 0; j < Allocation[i].size(); j++){
				if(Allocation[i][j] == k){
					MoveToEx(hDc,i*100+cnt,100,NULL);
					LineTo(hDc,k*100+cnt,50);
					cnt+=10;
				}
			}
			
			cnt = 5;
			for(j = 0; j < Need[i].size(); j++){
				if(Need[i][j] == k){
					MoveToEx(hDc,i*100+50+cnt,100,NULL);
					LineTo(hDc,k*100+cnt,50);
					cnt-=10;
				}
			}
		}
}

3 化简模块的实现
预处理那些不申请任何资源便可以运行的进程(即把它的占有资源添加到work数组中)。然后进入化简的主体部分,这时,需要设置一个标志以表示这轮扫描是否化简了进程,若这轮扫描化简了进程,则应该进行下一轮扫描,因为可能这轮释放的资源可以使用前不可以化简的进程在下一轮扫描时被化简。否则,不再进行下一轮扫描。然后,把所有的未被化简的进程放到一个Vector中。判断这个Vector是否为空,不为空则表示有进程发生了死锁。输出相应的提示信息后,初始化DFS在中需要的一些数据结构。然后,对每一个死锁进程,若它未被访问过,则由它作为入口,进入DFS,搜索所有和它的死锁有关系的进程和资源。当搜索结束后,输出相关的资源(相关的进程已经在DFS中输出)。若Vector为空,则表示所有的进程都顺利的运行完,则只要简单的输出提示信息即可。

void predigest(){
	Draw();
	bool finish[500];		//记录进程是否完成
	for(int index = 0; index < pro_size; index++){
		if(Need[index].size() != 0){
			finish[index] = false;
		}
		else{
			finish[index] = true;
			ers(index);
			for(int i = 0; i < Allocation[index].size(); i++)
				work[ Allocation[index][i] ]++;
		}		//此时就可以回收资源
	}

	bool flag;
	do{
		flag = false;
		for(int i = 0; i < pro_size; i++)
			if(!finish[i]){
				int temp[500];
				memset(temp,0,500);

				for(int k = 0; k < Need[i].size(); k++){
					temp[Need[i][k]]++;
				}

				bool ok = true;
				for(int j = 0; j < res_size; j++)
					if(temp[j] > work[j]){
						ok = false;
						break;
					}//可以分配?
				if(ok){
					ers(i);
					for(int t = 0; t < Allocation[i].size(); t++){
						work[Allocation[i][t]]++;
					}	//回收资源
					Allocation[i].clear();
					finish[i] = true;
					flag = true;
				}
			}
	}while(flag);

	for(int i = 0; i < pro_size; i++)
		if(finish[i] == false)
			Deadlock.push_back(i);

	if(Deadlock.size() != 0){
		cout << "发现死锁!" << endl << endl;
		cout << "与死锁有关的进程和资源是: " << endl;
		visited = new bool[Deadlock.size()+5];		//use to id wheather the pro is visited DFS
		memset(visited,0,Deadlock.size()+5);
		Dead_res = new bool[res_size+5];

		for(int i = 0; i < Deadlock.size(); i++){
			if(!visited[i]){
				memset(Dead_res,0,res_size+5);
				DeadlockChain(i);
				cout << "Resource: ";
				for(int j = 0; j < res_size; j++)
					if(Dead_res[j])
						cout << j << " ";
			}
			cout << endl;
		}
	}
	else
		cout << "未发现死锁!" << endl;
} 

运行结果

银行家算法运行结果
在这里插入图片描述
自行设置合理的Allocation,Max,Need矩阵和Available向量。
在这里插入图片描述
进行安全性算法检查时,要求能实时显示各进程申请和释放资源的过程,为此定义Work和Need1矩阵开表示资源变化情况。
在这里插入图片描述
当一进程申请资源时,要比对Available与自身Need值和其要申请的值,满足条件才能进行安全性算法,否则提示出错。
在这里插入图片描述
最终结果要求能给出系统是否安全的结论以及符合条件的一条安全序列。

死锁检测算法运行结果
在这里插入图片描述
本文实现的是课本P116-P117的代码,因此将资源类数,资源数,进程数,进程占用资源数,请求资源数设置为如上图所示。
在这里插入图片描述
在这里插入图片描述
化简过程
在这里插入图片描述
输出结果

由于篇幅原因,完整代码在此不进行粘贴,我将所有的代码以及报告文档打包为一个压缩包,请点击
链接: 点我.

温馨提示:有任何问题,可以在留言区留言,我会回答大家的问题,觉得对你有帮助的,可以关注一下,我会定期更新博客,内容很广。

发布了44 篇原创文章 · 获赞 97 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44573410/article/details/98878076