c/c++多线程模拟系统资源分配(并通过银行家算法避免死锁产生)

 

银行家算法数据结构 
(1)可利用资源向量Available 
是个含有m个元素的数组,其中的每一个元素代表一类可利用的资源数目。如果Available[j]=K,则表示系统中现有Rj类资源K个。 

(2)最大需求矩阵Max 
这是一个n×m的矩阵,它定义了系统中n个进程中的每一个进程对m类资源的最大需求。如果Max[i,j]=K,则表示进程i需要Rj类资源的最大数目为K。 

(3)分配矩阵Allocation 
这也是一个n×m的矩阵,它定义了系统中每一类资源当前已分配给每一进程的资源数。如果Allocation[i,j]=K,则表示进程i当前已分得Rj类资源的 数目为K。 
(4)需求矩阵Need。 
这也是一个n×m的矩阵,用以表示每一个进程尚需的各类资源数。如果Need[i,j]=K,则表示进程i还需要Rj类资源K个,方能完成其任务。 
Need[i,j]=Max[i,j]-Allocation[i,j]

银行家算法 
  在避免死锁的方法中,所施加的限制条件较弱,有可能获得令人满意的系统性能。在该方法中把系统的状态分为安全状态和不安全状态,只要能使系统始终都处于安全状态,便可以避免发生死锁。 
银行家算法的基本思想是分配资源之前,判断系统是否是安全的;若是,才分配。它是最具有代表性的避免死锁的算法。 
设进程cusneed提出请求REQUEST [i],则银行家算法按如下规则进行判断。

 (1)如果REQUEST [cusneed] [i]<= NEED[cusneed][i],则转(2);否则,出错。

 (2)如果REQUEST [cusneed] [i]<= AVAILABLE[i],则转(3);否则,等待。 

 (3)系统试探分配资源,修改相关数据: 

    AVAILABLE[i]-=REQUEST[cusneed][i]; 
    ALLOCATION[cusneed][i]+=REQUEST[cusneed][i]; 

    NEED[cusneed][i]-=REQUEST[cusneed][i]; 
(4)系统执行安全性检查,如安全,则分配成立;否则试探险性分配作废,系统恢复原状,进程等待。 安全性检查算法 
  1)设置两个工作向量Work=AVAILABLE;FINISH 

  2)从进程集合中找到一个满足下述条件的进程, FINISH==false; NEED<=Work; 
  如找到,执行(3);否则,执行(4) 
  3)设进程获得资源,可顺利执行,直至完成,从而释放资源。 Work=Work+ALLOCATION; Finish=true; GOTO 2)
  4)如所有的进程Finish= true,则表示安全;否则系统不安全。

#include<iostream>
#include<cstdio>
#include<vector>
#include<ctime>
#include<cstring>
#include<unistd.h>
#include<cstdlib>
#define RESTYPE  100  //资源的种类数 
#define NTHREAD  50      //线程的数目 
using namespace std;pthread_mutex_t mutex;//互斥信号量
pthread_cond_t cond;//条件变量 class BankerAlgorithm {//银行家算法 public:int nthread;//线程数int restThread;//剩余正在执行的线程数目 int nres;//资源数 int vis[NTHREAD];//标示这个进程有没有访问过 int threadFinished[NTHREAD];//标示这个线程是否已经结束 vector<int> resMax[NTHREAD];//每个线程对各类资源的最大的需求量vector<int> resAllocation[NTHREAD];//每个线程当前应经分配到各类资源的情况vector<int> resNeed[NTHREAD];//每个线程还需要每类资源的情况 vector<int> resAvailable;//各类资源的剩余可以利用的 private:void toNeed(){for(int i=0; i<nthread; ++i)for(int j=0; j<nres; ++j)resNeed[i].push_back(resMax[i][j]), resAllocation[i].push_back(0);} bool threadAafetyDetection(int idThread){//线程安全检测 vector<int> tmpResAvailable(resAvailable);vector<int> threadSafeSequence;//线程安全序列 int cntThread = 0;memset(vis, 0, sizeof(vis));while(threadSafeSequence.size() < restThread){bool findRunThread = false;for(int i=0; i<nthread; ++i)if(!vis[i] && !threadFinished[i]){int j;for(j=0; j<nres; ++j)if(resNeed[i][j] > tmpResAvailable[j]) break;if(j >= nres){//各类所需要的资源的数目 小于或等于各类剩余资源的数目 //该进程可以成功的运行完毕findRunThread = true;vis[i] = 1;threadSafeSequence.push_back(i);for(j=0; j<nres; ++j) tmpResAvailable[j] +=  resAllocation[i][j];}}if(!findRunThread) break;//找不到下一个可以运行的线程,则退出 
            }if(threadSafeSequence.size() == restThread){cout<<"此时系统处于安全状态,存在线程安全序列如下:"<<endl;for(int i=0; i<threadSafeSequence.size(); ++i) cout<<threadSafeSequence[i]<<" ";cout<<endl;return true;} else {cout<<"此时系统处于不安全状态!!!资源无法分配!!!进程"<<idThread<<"将被阻塞!!!"<<endl;//等到下一次resAvailable更新的时候再将该进程唤醒 return false;}}public:BankerAlgorithm(){}void init(){memset(threadFinished, 0, sizeof(threadFinished));//初始化线程的数目, 资源种类的数目以及每种资源的数目cout<<"请输入线程的数目和资源的种类数目:"<<endl;cin>>nthread>>nres;restThread = nthread; cout<<"请输入每种资源的数目:" <<endl;for(int i=0; i<nres; ++i){int k;cin>>k;resAvailable.push_back(k);}cout<<"请输入每个线程对某类资源最大的需求:"<<endl;for(int i=0; i<nthread; ++i){cout<<"线程"<<i<<"需要的资源:"<<endl; for(int j=0; j<nres; ++j){int k;cin>>k;resMax[i].push_back(k);}}toNeed(); }void returnRes(int idThread){for(int i=0; i<nres; ++i)resAvailable[i] += resAllocation[idThread][i], resAllocation[idThread][i]=0;}int bankerAlgorithm(int idThread, vector<int>res){//进程idThread对资源idRes的请求数量为kfor(int i=0; i<res.size(); ++i){int idRes=i, k = res[i];if(k <= resNeed[idThread][idRes]){if(k > resAvailable[idRes]){//让进程阻塞cout<<"ERROR!!!线程"<<idThread<<"请求"<<idRes<<"类资源数目大于该类剩余资源的数目!"<<endl<<endl; return 1;}} else {//让进程重新请求资源 cout<<"ERROR!!!线程"<<idThread<<"请求"<<idRes<<"类资源数目大于所需要的该类资源的数目!"<<endl<<endl; return 2;}}for(int i=0; i<res.size(); ++i){int idRes=i, k = res[i];resAvailable[idRes] -= k;resAllocation[idThread][idRes] += k;resNeed[idThread][idRes] -= k;}//安全性算法的检测if(!threadAafetyDetection(idThread)){//不能分配资源, 要将idThread这个线程阻塞 for(int i=0; i<res.size(); ++i){int idRes=i, k = res[i];resAvailable[idRes] += k;resAllocation[idThread][idRes] -= k;resNeed[idThread][idRes] += k;}return 3; }    cout<<"线程"<<idThread<<"获得资源:";for(int i=0; i<res.size(); ++i)cout<<" "<<i<<"类:"<<res[i];cout<<endl<<endl;return 0;}
};BankerAlgorithm ba;void *thread_hjzgg(void *arg){long long idThread = (long long)arg;//得到线程的标号srand((int)time(0));//开始进行线程资源的请求vector<int> res;for(int i=0; i<ba.nres; ++i){int k = ba.resNeed[idThread][i] == 0 ? 0 : rand() % ba.resNeed[idThread][i]+1;//线程对资源i申请的数目 
        res.push_back(k);}while(1){if(pthread_mutex_lock(&mutex)!=0){cout<<"线程"<<idThread<<"加锁失败!!!"<<endl;pthread_exit(NULL);}bool isAllocationFinished = true;//该线程是否已经将资源请求完毕 for(int i=0; i<ba.nres; ++i) if(ba.resNeed[idThread][i] != 0){isAllocationFinished = false;break;}if(isAllocationFinished){cout<<"线程"<<idThread<<"资源分配完毕!!!进程得到想要的全部资源后开始继续执行!"<<endl; cout<<"................"<<endl;sleep(1);cout<<"线程"<<idThread<<"执行完毕!!!"<<endl<<endl;--ba.restThread;ba.threadFinished[idThread] = 1;//线程结束 
            ba.returnRes(idThread);pthread_cond_broadcast(&cond);pthread_mutex_unlock(&mutex);pthread_exit(NULL);}switch(ba.bankerAlgorithm(idThread, res)){case 3://系统会进入不安全状态,不能进行资源的分配,先进行阻塞 case 1://进程阻塞 pthread_cond_wait(&cond, &mutex);break;case 2://重新分配资源 case 0://资源分配成功, 接着在申请新的资源 
                res.clear();for(int i=0; i<ba.nres; ++i){int k = ba.resNeed[idThread][i] == 0 ? 0 : rand() % ba.resNeed[idThread][i]+1;//线程对资源i申请的数目 
                    res.push_back(k);}break;default:break;}sleep(1);pthread_mutex_unlock(&mutex);}
} int main(){pthread_t tid[NTHREAD];pthread_mutex_init(&mutex, NULL);pthread_cond_init(&cond, NULL);ba.init();for(int i=0; i<ba.nthread; ++i)pthread_create(&tid[i], NULL, thread_hjzgg, (void*)i);for(int i=0; i<ba.nthread; ++i)pthread_join(tid[i], NULL);return 0;
} 
/*
5 3
10 8 6
2 1 3
6 1 1
3 2 2
6 2 1
2 1 1此时系统处于安全状态,存在线程安全序列如下:
0 1 2 3 4
线程0获得资源: 0类:2 1类:1 2类:3此时系统处于安全状态,存在线程安全序列如下:
0 1 2 3 4
线程1获得资源: 0类:6 1类:1 2类:1ERROR!!!线程2请求0类资源数目大于该类剩余资源的数目!此时系统处于安全状态,存在线程安全序列如下:
0 1 2 3 4
线程4获得资源: 0类:2 1类:1 2类:1ERROR!!!线程3请求0类资源数目大于该类剩余资源的数目!线程0资源分配完毕!!!进程得到想要的全部资源后开始继续执行!
................
线程0执行完毕!!!线程1资源分配完毕!!!进程得到想要的全部资源后开始继续执行!
................
线程1执行完毕!!!线程4资源分配完毕!!!进程得到想要的全部资源后开始继续执行!
................
线程4执行完毕!!!此时系统处于安全状态,存在线程安全序列如下:
2 3
线程3获得资源: 0类:6 1类:2 2类:1此时系统处于安全状态,存在线程安全序列如下:
2 3
线程2获得资源: 0类:3 1类:2 2类:2线程3资源分配完毕!!!进程得到想要的全部资源后开始继续执行!
................
线程3执行完毕!!!线程2资源分配完毕!!!进程得到想要的全部资源后开始继续执行!
................
线程2执行完毕!!!*/

 

转载于:https://www.cnblogs.com/hujunzheng/p/4820796.html

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

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

相关文章

(四)Linux内核模块化编程

目录&#xff08;一&#xff09;模块化编程简介&#xff08;二&#xff09;安装卸载模块命令.&#xff08;三&#xff09;将自定义功能添加到内核三种方法&#xff08;1&#xff09;修改Kconfig和Makefile&#xff08;2&#xff09;直接修改功能对应目录下的Makefile文件&#…

基于X86平台的PC机通过网络发送一个int(32位)整数的字节顺序

1.字节顺序  字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序&#xff0c;通常有小端、大端两种字节顺序。小端字节序指低字节数据存放在内存低地址处&#xff0c;高字节数据存放在内存高地址处&#xff1b;大端字节序是高字节数据存放在低地址处&#xff0c;低字…

Linux内核空间和用户空间

在Linux系统中存在进程的概念&#xff1a; 进程的分类&#xff1a; 用户进程&#xff1a;运行在用户空间的进程被称为用户进程 内核进程:运行在内核空间的进程被称为内核进程 进程的空间&#xff1a; 系统会为每一个进程分0-4G的虚拟寻址空间&#xff0c;在4G的空间中 0-3G&…

codeforces Round #320 (Div. 2) C. A Problem about Polyline(数学) D. Or Game(暴力,数学)

解题思路&#xff1a;就是求数 n 对应的二进制数中有多少个 1 #include <iostream> #include<cstdio> using namespace std; int main(){int n;cin>>n;int ans 0; // while(n){//这也是一种好的方法 // n n&(n-1); // ans; // }while(n…

(五)Linux之设备驱动模型

目录&#xff08;一&#xff09;Linux内核驱动简介&#xff08;二&#xff09;杂项设备驱动模型&#xff08;1&#xff09;相关接口&#xff08;2&#xff09;杂项设备注册过程&#xff08;三&#xff09;早期经典字符设备驱动模型&#xff08;1&#xff09;相关接口&#xff0…

操作系统页面置换算法(opt,lru,fifo,clock)实现

选择调出页面的算法就称为页面置换算法。好的页面置换算法应有较低的页面更换频率&#xff0c;也就是说&#xff0c;应将以后不会再访问或者以后较长时间内不会再访问的页面先调出。 常见的置换算法有以下四种&#xff08;以下来自操作系统课本&#xff09;。 1. 最佳置换算法(…

(六)Linux之设备驱动模型(续)

前面我们学习了杂项设备驱动模型、早期经典字符设备驱动模型,这一小节来讲解Linux中的标准字符设备驱动。 目录&#xff08;一&#xff09;为什么引入标准字符设备驱动模型&#xff08;二&#xff09;相关接口&#xff08;三&#xff09;注册流程&#xff08;四&#xff09;程序…

N个数依次入栈,出栈顺序有多少种?

对于每一个数来说&#xff0c;必须进栈一次、出栈一次。我们把进栈设为状态‘1’&#xff0c;出栈设为状态‘0’。n个数的所有状态对应n个1和n个0组成的2n位二进制数。由于等待入栈的操作数按照1‥n的顺序排列、入栈的操作数b大于等于出栈的操作数a(a≤b)&#xff0c;因此输出序…

(七)linux函数接口的使用

前面我们讲解了字符设备的驱动模型&#xff0c;有了前面的基础后&#xff0c;今天学习函数接口就比较容易了 目录&#xff08;一&#xff09;open函数接口&#xff08;二&#xff09;read函数接口&#xff08;三&#xff09;lseek函数接口&#xff08;四&#xff09;用户空间和…

(八)linux驱动之ioctl的使用

这篇文章给大家讲解一下ioctl的简单使用&#xff0c;关于ioctl更详细的教程后面有机会单独写出来 &#xff08;一&#xff09;什么是ioctl ioctl是设备驱动程序中对设备的I/O通道进行管理的函数。所谓对I/O通道进行管理&#xff0c;就是对设备的一些特性进行控制&#xff0c;例…

(九)linux中断编程

目录&#xff08;一&#xff09;linux中断的介绍&#xff08;二&#xff09;内核中断的操作过程&#xff08;三&#xff09;实例代码&#xff08;一&#xff09;linux中断的介绍 linux内核中的中断通过中断子系统来管理。linux系统中有专门的中断子系统&#xff0c;原理很复杂…

网络爬虫(1)

参考&#xff1a;http://www.cnblogs.com/dongkuo/p/4851735.html算法分析我们现在从需求中提取关键词来逐步分析问题。 首先是“种子节点”。它就是一个或多个在爬虫程序运行前手动给出的URL&#xff08;网址&#xff09;&#xff0c;爬虫正是下载并解析这些种子URL指向的页面…

(十)Linux之等待队列

&#xff08;一&#xff09;阻塞和非阻塞 阻塞&#xff1a;执行设备操作时&#xff0c;若不能获得资源&#xff0c;则挂起进程进入休眠直到满足可操作的条件后再操作。 非阻塞&#xff1a;进程在不能进行设备操作时&#xff0c;并不挂起&#xff0c;它要么放弃&#xff0c;要么…

(十一)linux之poll轮询

目录&#xff08;一&#xff09;poll轮询的作用&#xff08;二&#xff09;poll轮询相关的接口&#xff08;三&#xff09;poll使用流程&#xff08;四&#xff09;实例代码&#xff08;一&#xff09;poll轮询的作用 以阻塞的方式打开文件&#xff0c;那么对多个文件读写时&a…

校验码(海明校验,CRC冗余校验,奇偶校验)

循环冗余校验码 CRC码利用生成多项式为k个数据位产生r个校验位进行编码,其编码长度为nkr所以又称 (n,k)码. CRC码广泛应用于数据通信领域和磁介质存储系统中. CRC理论非常复杂,一般书就给个例题,讲讲方法.现在简单介绍下它的原理: 在k位信息码后接r位校验码,对于一个给定的(n,k…

(十二)linux内核定时器

目录&#xff08;一&#xff09;内核定时器介绍&#xff08;二&#xff09;内核定时器相关接口&#xff08;三&#xff09;使用步骤&#xff08;四&#xff09;实例代码&#xff08;一&#xff09;内核定时器介绍 内核定时器并不是用来简单的定时操作&#xff0c;而是在定时时…

java Proxy(代理机制)

我们知道Spring主要有两大思想&#xff0c;一个是IoC&#xff0c;另一个就是AOP&#xff0c;对于IoC&#xff0c;依赖注入就不用多说了&#xff0c;而对于Spring的核心AOP来说&#xff0c;我们不但要知道怎么通过AOP来满足的我们的功能&#xff0c;我们更需要学习的是其底层是怎…

(十三)linux中断底半部分处理机制

这篇文章介绍一下linux中断的底半部分的tasklet和workquene两种处理机制&#xff0c;其中tasklet中不能有延时函数&#xff0c;workquene的处理函数可以加入延时操作 目录&#xff08;一&#xff09;tasklet小任务处理机制&#xff08;1&#xff09;tasklet相关函数接口&#x…

Codeforces Round #326 (Div. 2) B. Pasha and Phone C. Duff and Weight Lifting

B. Pasha and PhonePasha has recently bought a new phone jPager and started adding his friends phone numbers there. Each phone number consists of exactly n digits. Also Pasha has a number k and two sequences of length n / k (n is divisible by k) a1, a2, …

vmware中装的ubuntu上不了网

本文章针对桥接方式进行讲解&#xff0c;如果需要另外两种连接方式请参考文末给出的链接 &#xff08;一&#xff09;问题 主机和虚拟机可以相互ping通&#xff0c;但是却不能ping网址 &#xff08;二&#xff09;解决办法 vmware为我们提供了三种网络工作模式&#xff0c;…