操作系统实验二死锁避免之银行家算法的模拟

news2024/11/13 9:22:21

文章目录

死锁

 (1)定义

 (2)死锁产生的原因

 (3)死锁产生的必要条件

 (4)死锁的处理策略

银行家算法

 (1)核心思想

 (2)数据结构

 (3)算法描述

   (4)  安全性检查算法

银行家算法的模拟

(1)数据结构

(2)完整代码

(3)测试


死锁

(1)定义

所谓死锁,是指多个进程因为竞争资源而导致的一种互相循环等待的“僵局”,若无外力作用调整,这些进程都无法向前推进运行。

如下图所示,在十字路口,甲车在等着乙车来让道给自己通行,但乙车司机脾气暴躁就是不让也在等待着甲车让道给自己通行,互相等待,谁都不让道,从而造成一种拥堵的僵局现象,这就是生活中常见的死锁现象。

 (2)死锁产生的原因

  • 系统资源的竞争
  • 进程推进的顺序非法
  • 信号量使用不当

(3)死锁产生的必要条件

  • 互斥条件:进程要求对所分配的资源进行排他性使用,即在某段时间内某种资源只能被一种进程独自使用
  • 不可剥夺条件:进程在获得资源后不能被其它进程强行夺走,而是由自己主动释放
  • 请求并保持条件:进程已经保持了一种资源,但又提出了新的资源请求,而该资源已经被其它进程所占用,此时请求进程被阻塞,但对自己已经获得的资源保持不放
  • 循环等待条件:存在一种进程资源的循环等待链,链中的每个进程所获得的资源同时被下一个资源所请求。如上图2-15所示

 

(4)死锁的处理策略

  • 死锁预防:设置某些限制条件,破坏产生死锁4个必要条件中的一个或几个
  • 死锁避免:在资源的动态分配中,用某种方法防止系统进入不安全状态
  • 死锁的检测与解除:无需采用任何的限制性措施,允许进程发生死锁。通过系统的检测机制来检测到死锁,并采取某种措施来解除死锁

而下面所讲的银行家算法就属于死锁避免算法的一种。


银行家算法

(1)核心思想

        银行家算法是最著名的死锁避免算法,其思想是:把操作系统视为银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求分配资源相当于用户向银行家款。操作系统按照银行家制定的规则为进程分配资源。进程运行之前先声明对各种资源的最大需求量,当进程在执行中继续申请资源时,先测试该进程已占用的资源数与本次申请的资源数之和是否超过该进程声明的最大需求量。若超过则拒绝分配资源,若未超过则再测试系统现存的资源能否满足该进程尚需的最大资源量,若能满足则按当前的申请量分配资源,否则也要推迟分配

(2)数据结构

  • 可用资源向量Available:长度为n的数组表示系统中n类资源的当前可用数目。如果Available[j]=k,表示系统中现有Rj类资源为k个。

  • 最大需求矩阵Max:m×n矩阵定义m个进程对n类资源的最大需求量。如Max[i,j]=k,表示进程Pi运行期间最多需求Rj资源的数目为k个。

  • 已分配资源矩阵Allocation:m×n矩阵定义了每个进程现在已分配到的各类资源的实际数目。如果Allocation [i,j]=k,表示进程Pi当前分到k个Rj类资源。

  •  需求矩阵Need:m×n矩阵表示每个进程还需要的各类资源的数目。如果Need [i, j]=k,表示进程Pi尚需k个Rj类资源才能完成其任务。很显然,Need[i,j]=Max[i,j] - Allocation[i,j],因而,这些数据结构的大小和值会随着时间而改变。

 其中,Need=Max-Allocation

 (3)算法描述

设Requesti表示进程Pi的资源申请向量。如Requesti[j]= k,表示进程Pi动态申请k个Rj类资源。当进程Pi申请资源时,就执行下列动作(试探性分配):

  1. 若Requesti[j]>Need[i,j],产生出错条件,因为进程Pi对资源的请求量已超过其说明的最大数量;否则,转到步骤2。

  2. 如果Requesti[j]>Available[j],则进程Pi必须等待,这是因为系统现在没有可用的资源;否则,转到步骤3。

  3. 如果系统可以给进程Pi分配所请求的资源,则应对有关数据结构进行修改:
            Available[j] = Available[j]-Requesti[j];   (j=1,2,……,n)
            Allocation[i,j] = Allocation[i,j] + Requesti[j];   (i=1,2,……,m)
            Need[i,j] = Need[i,j] - Requesti[j];

  4. 系统执行安全性检查,查看此时系统状态是否安全。如果安全,就给进程Pi 实际分配资源;否则,即系统是不安全的,则Pi等待,作废本次试探性分配,并且把资源分配状态恢复成3之前的情况。

(4)安全性检查算法

        安全性检查算法是银行家算法的核心,在银行家算法的习题中,一般会有某个进程发出一个资源请求向量,我们只需要执行上面银行家算法的前三步,就会得到一个更新后的Allocation和Need矩阵,再按照上例的安全性算法进行判断,此时系统是否处于安全状态,就能直到系统是否能立即满足该进程提出的资源请求。

一般步骤如下:

  1. 设置两个向量:工作向量Work:表示系统可提供给进程继续运行所需要的各类资源数目,长度为n;进程完成标志向量Finish:长度为m,表示各个进程是否能够得到足够的资源并运行完成。两个向量初始化:Work=AvailableFinish[i]=false (i=1,2,...m)

  2. 从进程集合中搜寻满足下列条件的进程(找安全进程序列):Finish[i] ==false且Need[i,j]≤Work[j]。如果找到这样的进程,执行3;否则,则转向步骤4。

  3. 修改数据值:Work[j]=Work[j] + Allocation[i,j](进程Pi释放所占的全部资源);Finish[i]=true;返回步骤2

  4. 安全状态的判定:如果所有进程的Finish[i] ==true都成立(找着安全序列),则系统处于安全状态;否则,系统处于不安全状态

 


 

银行家算法的模拟

(1)数据结构

//定义银行家算法的数据结构 
int Available[3]={3,3,2};//系统可用资源 
int Max[5][3]={{7,5,3},{3,2,2},{9,0,2},{2,2,2},{4,3,3}};//进程最大资源需求量 
int Allocation[5][3]={{0,1,0},{2,0,0},{3,0,2},{2,1,1},{0,0,2}};//系统已经给进程分配的资源 
int Need[5][3]={{7,4,3},{1,2,2},{6,0,0},{0,1,1},{4,3,1}};//进程的资源最大需求量 
int Work[3];//安全性检查算法中的工作向量 
int Finish[5]={0,0,0,0,0};//进程执行完成的标志 
int SafeArray[5];//安全序列 
int Request[3];//请求资源向量 

(2)完整代码

/*
	模拟银行家算法,进行死锁的避免 
*/
#include<iostream>
using namespace std;
//定义银行家算法的数据结构 
int Available[3]={3,3,2};//系统可用资源 
int Max[5][3]={{7,5,3},{3,2,2},{9,0,2},{2,2,2},{4,3,3}};//进程最大资源需求量 
int Allocation[5][3]={{0,1,0},{2,0,0},{3,0,2},{2,1,1},{0,0,2}};//系统已经给进程分配的资源 
int Need[5][3]={{7,4,3},{1,2,2},{6,0,0},{0,1,1},{4,3,1}};//进程的资源最大需求量 
int Work[3];//安全性检查算法中的工作向量 
int Finish[5]={0,0,0,0,0};//进程执行完成的标志 
int SafeArray[5];//安全序列 
int Request[3];//请求资源向量 

void ShowSafe(int i);
//打印当前系统资源的分配情况 
void Show(){
    cout<<"T0时刻的系统资源分配情况如下:"<<endl;
    cout<<"进程名\tMax\t\tAllocation\tNeed\t\tAvailable"<<endl;
    for(int i=0;i<5;i++){
        cout<<"P"<<i<<"\t";
        for(int j=0;j<3;j++){
            cout<<Max[i][j]<<" ";
        }
        cout<<"\t\t";
        for(int j=0;j<3;j++){
            cout<<Allocation[i][j]<<" ";
        }
        cout<<"\t\t";
        for(int j=0;j<3;j++){
            cout<<Need[i][j]<<" ";
        }
        cout<<"\t\t";
        if(i==0){
            for(int j=0;j<3;j++){
                cout<<Available[j]<<" ";
            }
        }
        cout<<endl;
    }
}
//安全性检查中判断需求矩阵与工作向量关系 
int NeedLessWork(int i){
    for(int j=0;j<3;j++){
        if(Need[i][j]>Work[j]){
            return 0;
        }
    }
    return 1;
}
//打印安全序列 
void SafeLine(){
    cout<<"当前系统处于安全状态..."<<endl;
    cout<<"其中一个安全序列为:" ;
    for(int i=0;i<5;i++){
    	if(i==4)cout<<"P"<<SafeArray[i];
    	else cout<<"P"<<SafeArray[i]<<"-->";
    }
    cout<<endl;
    for(int i=0;i<5;i++){
        Finish[i]=0;
    }
}

//安全性检查算法 
void IsSafe(int index){
    for(int i=0;i<5;i++){
        int temp=NeedLessWork(i);
        if(Finish[i]==0&&temp){
            SafeArray[index]=i;
            index++;
            Finish[i]=1;
            ShowSafe(i);
            for(int j=0;j<3;j++){
                Work[j]=Work[j]+Allocation[i][j];
            }
            break;
        }
    }
    int mult=1;
    //如果五个标志都为1即都已经完成,则打印安全序列,否则继续执行安全性检查算法 
    for(int k=0;k<5;k++){
        mult*=Finish[k];
    }
    if(mult==0){
        IsSafe(index);
    }else{
        SafeLine();
    }
}
void ShowSafe(int i){
    cout<<"P"<<i<<"\t";
    for(int j=0;j<3;j++){
        cout<<Work[j]<<" ";
    }
    cout<<"\t\t";
    for(int j=0;j<3;j++){
        cout<<Need[i][j]<<" ";
    }
    cout<<"\t\t";
    for(int j=0;j<3;j++){
        cout<<Allocation[i][j]<<" ";
    }
    cout<<"\t\t";
    for(int j=0;j<3;j++){
        cout<<Work[j]+Allocation[i][j]<<" ";
    }
    cout<<"\t\t";
    cout<<Finish[i];
    cout<<endl;

}
void SafeCheck(){
    cout<<"试探着将资源分配给它后,系统安全情况分析如下:"<<endl;
    cout<<"进程\tWork\t\tNeed\t\tAllocation\tWork+Allocation\tFinish"<<endl;
    for(int i=0;i<3;i++){
        Work[i]=Available[i];
    }
    IsSafe(0);
}

int RequestLessNeed(int i){
    for(int j=0;j<3;j++){
        if(Request[j]>Need[i][j]){
            return 0;
        }
    }
    return 1;
}
int RequestLessAvailable(int i){
    for(int j=0;j<3;j++){
        if(Request[j]>Available[j]){
            return 0;
        }
    }
    return 1;
}

//处理进程发出的资源请求 
void RequestResourse(){
    cout<<"请输入发出资源请求的进程:";
    int n;
	cin>>n;
    cout<<"请依次输入所请求的资源数量:";
    for(int i=0;i<3;i++){
        cin>>Request[i];
    }
    if(RequestLessNeed(n)){
    	if(RequestLessAvailable(n)){
    		for(int j=0;j<3;j++){
            Available[j]=Available[j]-Request[j];
            Allocation[n][j]=Allocation[n][j]+Request[j];
            Need[n][j]=Need[n][j]-Request[j];
           }
            SafeCheck();//试探着将资源分配给请求进程,并进行安全性检查 
    	}else{
    		cout<<"P"<<n<<"请求的资源向量已超过系统可用资源向量,请求失败!让其继续等待..."<<endl;
    		cout<<"-------------------------------------------------------------------"<<endl; 
            return ;
    	}
    }else{
    	 cout<<"P"<<n<<"请求的资源向量已超过其最大需求向量,请求失败!让其继续等待..."<<endl;
    	 cout<<"-------------------------------------------------------------------"<<endl; 
         return ;
    }
}


int main(){
    cout<<"*************************银行家算法的模拟*************************"<<endl;
    cout<<"    \t\t\t1.显示当前系统资源情况"<<endl;
    cout<<"    \t\t\t2.进程发出请求向量"<<endl;
    cout<<"    \t\t\t3.退出系统"<<endl;
    cout<<"******************************************************************"<<endl; 
    while(true){
        int choose;
        cout<<"请选择你要执行的操作:";
        cin>>choose;
        switch (choose){
            case 1 :
                Show();//展示当前系统资源分配情况 
                break;
            case 2:
                RequestResourse();//处理进程发出的资源请求 
                break;
            case 3:
                cout<<"已退出系统!"<<endl;
                return 0;
            default:
                cout<<"输入错误,请重新输入!"<<endl;
                continue;
        }
    }
}

(3)测试

 综上。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2296.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2.2 Pycharm 的使用

文章目录1. PyCharm 安装2. Python 项目3. 外貌设置4. 配色方案5. 字体大小6. 自动换行7. 汉化8. 翻译插件9. 添加多个解释器10. Pycharm 常用快捷键11. 自定义文件模板内容12. 前端代码运行浏览器13. 关闭 with open 提示14. 双击shift查找15. 导出配置导入配置1. PyCharm 安装…

Gwas实战分析3_群体结构增加

1.sh plink 格式转化 plink1.map/plink1.ped ------plink2.bim/fam/bed plink --file 1001genomes_snps_only_ACGTN1 --make-bed --out plink2 2.sh 群体结构分析 时间过久&#xff1a; for K in 2 3 4 5 6 7 8 9 10; do admixture --cv plink2.bed K∣teeadmixtrueK | tee…

HTML小游戏4 —— 简易版英雄联盟(附完整源码)

&#x1f482; 网站推荐:【神级源码资源网】【摸鱼小游戏】&#x1f91f; 风趣幽默的前端学习课程&#xff1a;&#x1f449;28个案例趣学前端&#x1f485; 想寻找共同学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】&#x1f4ac; 免费且实用的计算机相关知…

基于C#实现的在线聊天室的桌面系统软件

资源下载地址&#xff1a;https://download.csdn.net/download/sheziqiong/86863237 资源下载地址&#xff1a;https://download.csdn.net/download/sheziqiong/86863237 目录 个人聊天室软件 1 需求分析与概要设计 1 项目说明 1 1.1. 项目目标&#xff1a; 1 1.2. 软硬件环境…

庖丁解牛 指针的高端操作

本章重点 写在前面 1.字符指针 2.指针数组 3.数组指针 3.1数组指针的定义 3.2 &数组名VS数组名 3.3 数组指针的使用 二维数组与数组指针 4.数组参数和指指针参数 4.1一维数组传参 4.2 二维数组传参 4.3一级指针传参 4.4二级指针传参 5.函数指针 5.1函数指针的…

SSM基于小程序的医院预约挂号系统 毕业设计-附源码260839

SSM医院预约挂号小程序的设计与实现 摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对医院排…

Prometheus系列(2)之EC2安装Node端

目标 为Prometheus安装Node程序。 步骤 node exporter程序 wget https://github.com/prometheus/node_exporter/releases/download/v1.4.0/node_exporter-1.4.0.linux-amd64.tar.gz tar xvzf node_exporter-1.4.0.linux-amd64.tar.gz cd node_exporter-1.4.0.linux-amd64/s…

技术分享 | 专项测试技术初识Hook

本文节选自霍格沃兹测试学院内部教材Hook 技术需要预先分析目标应用的源代码和逻辑&#xff0c;根据目标测试场景设置目标、逻辑和数据&#xff0c;然后运行时动态的对目标函数参数值、逻辑或者返回值做修改&#xff0c;达到修改现有函数逻辑、实现目标测试场景的目的。 Hook的…

汇编语言指令

文章目录算术运算指令ADDADDISUB伪指令LUILIAUIPCLA逻辑运算指令内存读写指令条件分支指令无条件跳转指令算术运算指令 ADD 语法ADD RD&#xff0c;RS1,RS2例子add x5,x6,x7x5x6x7编码格式&#xff1a;R-type opcode(7):0110011(OP) 从RS里面取出数据&#xff0c;把里面的数据…

【MyBatis框架】关联映射

关系映射1. 关联映射概述2. 环境搭建3.处理字段名和属性名不一致的情况4. 处理一对一映射5. 处理多对一映射5.1 级联方式处理5.2 使用association处理映射关系5.3 分步查询6. 处理一对多查询7. 小结1. 关联映射概述 在关系型数据库中&#xff0c;多表之间存在着三种关联关系&a…

Linux文件打包及压缩、解包及解压

目录 前言 什么是压缩&#xff1f; tar的介绍与使用 简介 打包压缩文件 打包文件&#xff08;不压缩&#xff09; gzip压缩类型压缩文件 bzip压缩类型压缩文件 xzip压缩类型压缩文件 解包解压文件 简介 解压缩&#xff08;解压到当前目录&#xff09; 解压缩&#x…

线代 | 【提神醒脑】自用笔记串联

一、初等变换 1、初等行变换与方程组的同解变换 2、初等行变换关系网 ※ 3、关联结论 —— 同解方程 4、行、列变换适用场景

Java 线程池之ThreadPoolExecutor学习总结

前提 java version "1.8.0_25" 池简述 软件开发活动中&#xff0c;我们经常会听到数据库连接池、内存池、线程池等各种“池”概念&#xff0c;这些“池”到底是什么东西呢&#xff1f;程序的世界里&#xff0c;我们可以将池简单的理解为一种容器类数据结构&#x…

哪本计算机书籍,让你有了醍醐灌顶突然开悟的感觉?

计算机书籍每年都会出版很多&#xff0c;但是能影响几代程序员的有这几本书&#xff0c;推荐一下&#xff0c;肯定让你有醍醐灌顶的开悟的感觉。 1、重构 改善既有代码的设计&#xff08;第2版 平装版&#xff09; 豆瓣评分&#xff1a;9.2 本书是一本为专业程序员编写的重构指…

30岁本科男,在测试行业干了五年还只会功能测试,难道真的要去送外卖吗?

在网上看到一个帖子 从发帖内容可以看出&#xff0c;题主是一位拥有五年功能测试经验的IT从业者&#xff0c;他也深知功能测试现在的处境艰难&#xff0c;想改变&#xff0c;却又因为年龄和经济压力的原因迟迟不敢迈出第一步&#xff0c;其实这是很多年近30岁的人事业危机的缩影…

【Java】之File类

个人主页&#xff1a;天寒雨落的博客_CSDN博客-C,CSDN竞赛,python领域博主 特别标注&#xff1a;仅为自己的学习记录笔记&#xff0c;方便复习和加深记忆&#xff0c;仅供借鉴参考&#xff01; 前篇回顾&#xff1a;【java】之File类_天寒雨落的博客-CSDN博客 目录 目录的遍历…

五 系统安全分析与设计

目录 一、安全基础技术 1.1 对称与非对称加密 1.2 数字签名&#xff08;防抵赖&#xff09; 1.3 信息摘要&#xff08;防篡改&#xff09; 1.4 加密、数字签名、信息摘要结合使用 1.5 数字证书&#xff08;防止公钥被截取篡改&#xff09; 二、网络安全 2.1 安全协议 …

Android LayerDrawable 使用

1. 前言 Android LayerDrawble 包含一个Drawable数组&#xff0c;系统将会按照这些Drawable对象的数组顺序来绘制他们&#xff0c;索引最大的 Drawable 对象将会被绘制在最上面。 LayerDrawable对象的xml文件的根元素是<layer-list>&#xff0c; 该元素内部包含多个<i…

【Linux】开发工具之gdb调试器

目录&#x1f308;前言&#x1f337;1、debug与release&#x1f338;2、gdb选项&#x1f308;前言 本篇文章进行调试器gdb的学习&#xff01;&#xff01;&#xff01; &#x1f337;1、debug与release debug会生成需要调试的信息&#xff0c;release不会生成 程序的发布方式有…

【Node.js】模块的加载机制

✍️ 作者简介: 前端新手学习中。 &#x1f482; 作者主页: 作者主页查看更多前端教学 &#x1f393; 专栏分享&#xff1a;css重难点教学 Node.js教学 从头开始学习 目录 模块的加载机制 优先从缓存中加载 内置模块的加载机制 自定义模块的加载机制 第三方模块的加载机…