文章目录
掌握银行家算法思想,并能编程实现。
1、在Linux环境下编译运行程序;
2、按照教材的算法编写;
3、(*)输入数据从文本文件中读出,不从键盘录入,数据文件格式见以下说明;
4、主要数据结构的变量名和教材中的一致,包括Available、Max、Allocation、Need、Request、Work、Finish。
5、程序可支持不同个数的进程和不同个数的资源;
6、验证教材中的“银行家算法示例”中的例子(包括可成功分配、不可分配)。
要解释银行家算法,必须先解释操作系统安全状态和不安全状态。
那么什么是安全序列呢?
安全序列:一个进程序列{P1,…,Pn}是安全的,如果对于每一个进程Pi(1≤i≤n),它以后尚需要的资源量不超过系统当前剩余资源量与所有进程Pj (j < i)当前占有资源量之和。
银行家算法:
按银行家制定的规则为进程分配资源,可以使系统保持在安全状态,具体方法如下:
· 进程首次申请资源的分配
如果系统现存资源可以满足该进程的最大需求量,则按当前的申请量分配资源,否则推迟分配。
· 进程在执行中继续申请资源的分配
若该进程已占用的资源与本次申请的资源之和不超过对资源的最大需求量,且现存资源能满足该进程尚需的最大资源量,则按当前申请量分配资源,否则推迟分配。
· 至少一个进程能完成
在任何时刻保证至少有一个进程能得到所需的全部资源而执行到结束。
银行家算法通过动态地检测系统中资源分配情况和进程对资源的需求情况来决定如何分配资源,并能在确保系统处于安全状态时才把资源分配给申请者,从而避免系统发生死锁。
初始化:
由data文件中读取数据数据,分别对可利用资源向量矩阵Available、最大需求矩阵Max、分配矩阵Allocation、需求矩阵Need赋值。
银行家算法:
在避免死锁的方法中,所施加的限制条件较弱,有可能获得令人满意的系统性能。在该方法中把系统的状态分为安全状态和不安全状态,只要能使系统始终都处于安全状态,便可以避免发生死锁。
银行家算法的基本思想是分配资源之前,判断系统是否是安全的;若是,才分配。它是最具有代表性的避免死锁的算法。
设进程curProcess提出请求Request [i],则银行家算法按如下规则进行判断:
如果Request [curProcess] [i] <= NEED[curProcess][i],则转2;否则,出错。
如果Request [curProcess] [i] <= Available [i],则转3;否则,等待。
系统试探分配资源,修改相关数据:
Available[i] -= Request[cusneed][i];
Allocation[cusneed][i] += Request[cusneed][i];
Need[cusneed][i] -= Request[cusneed][i];
系统执行安全性检查,如安全,则分配成立;否则试探险性分配作废,系统恢复原状,进程等待。
安全性检查算法:
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
typedef int bool;
#define true 1
#define false 0
int processNum; //进程数
int resourcesNum; //资源数
int **Allocation; //各个进程已分配的各种资源数
int **Max; //各个进程最大需要的各种资源数
int **Need; //各个进程还需要的各种资源数
int *Available; //当前可用的各种资源数
int *Request; //当前进程请求的各资源数
bool *Finish; //记录各进程是否完成
int *safeSequence; //安全序列
//初始化
void init(char* argv[], int *flag1, FILE *fp) {
if(fp == NULL) {
printf("ERROR!\n");
*flag1 = 0;
return ;
}
//从文件中读取进程数和资源数
fscanf(fp, "%d", &processNum);
fscanf(fp, "%d", &resourcesNum);
//分配二维数组(Allocation、Max、Need)的大小
Allocation = (int**)malloc(processNum * sizeof(int*));
Max = (int**)malloc(processNum * sizeof(int*));
Need = (int**)malloc(processNum * sizeof(int*));
for(int i = 0;i < processNum; i++) {
Allocation[i] = (int*)malloc(resourcesNum * sizeof(int));
Max[i] = (int*)malloc(resourcesNum * sizeof(int));
Need[i] = (int*)malloc(resourcesNum * sizeof(int));
}
//分配一维数组大小(Available)
Available = (int*)malloc(resourcesNum * sizeof(int));
Finish = (int*)malloc(resourcesNum * sizeof(int));
safeSequence = (int*)malloc(processNum * sizeof(int));
//初始化系统剩余资源数(刚开始为最大资源数)
for(int i = 0; i < resourcesNum; i++){
fscanf(fp, "%d", &Available[i]);
}
//初始化已分配的资源矩阵和最大需求矩阵
int count = 0;
while(count < processNum) {
int curProcess; //当前进程号
fscanf(fp, "%d", &curProcess);
//从data文件中读取进程curProcessd的Allocation和Max
for(int i = 0; i < resourcesNum; i++) {
fscanf(fp, "%d", &Allocation[curProcess][i]);
}
for(int i = 0; i < resourcesNum; i++) {
fscanf(fp, "%d", &Max[curProcess][i]);
}
count++;
}
//初始化进程还需要的各种资源数(Need数组)
for(int i = 0;i < processNum; i++) {
for(int j = 0; j < resourcesNum; j++) {
Need[i][j] = Max[i][j] - Allocation[i][j];
}
}
//分配给各进程一定资源数后,更新系统剩余的资源数
for(int i = 0; i < resourcesNum; i++) {
for(int j = 0; j < processNum; j++) {
Available[i] = Available[i] - Allocation[j][i];
}
}
}
//打印当前时刻的安全序列表
void safeShow(int *Work, int curProcess) {
printf("P%d\t\t ", curProcess);
for(int j = 0; j < resourcesNum; j++) {
printf("%d ", Work[j]);
}
printf("\t\t ");
for(int j = 0; j < resourcesNum; j++) {
printf("%d ", Need[curProcess][j]);
}
printf("\t\t ");
for(int j = 0; j < resourcesNum; j++) {
printf("%d ", Allocation[curProcess][j]);
}
printf("\t\t\t ");
for(int j = 0; j < resourcesNum; j++) {
printf("%d ", Work[j] + Allocation[curProcess][j]);
}
printf("\n");
}
//判断当前系统是否处于安全状态
bool isSafe() {
int trueFinished = 0; //记录进程分配成功的个数
int *Work = (int*)malloc(resourcesNum * sizeof(int));
//初始化Work数组
for(int i = 0; i < resourcesNum; i++) {
Work[i] = Available[i];
}
//初始化Finish数组,开始时所有进程的资源都未分配成功
for(int i = 0; i < processNum; i++) {
Finish[i] = false;
}
int curProcess = 0; //当前进程号
//下面两个temp的作用是:对进程组的每一轮遍历后,即curProcess到头之后,检查一下trueFinished有没有增加。
int temp = 0; //记录这一次遍历的trueFinished
int temp0 = 0; //记录上一次遍历的trueFinished
int flag = 0; //记录是否是第一次遍历各个进程
while(trueFinished != processNum) {
int count = 0; //进程需要的资源数小于系统剩余的资源数的个数
//当前进程curProcess未完成分配
if(Finish[curProcess] == false) {
//检查是否进程需要的资源数是否都小于系统剩余的资源数
for(int i = 0; i < resourcesNum; i++) {
if(Need[curProcess][i] <= Work[i])
count++;
else break;
}
if(count == resourcesNum) {
Finish[curProcess] = true; //进程curProcess分配完成
safeShow(Work, curProcess);
//将分配给curProcess的资源回收
for(int i = 0; i < resourcesNum; i++) {
Work[i] += Allocation[curProcess][i];
}
//将curProcess例如安全序列
safeSequence[trueFinished] = curProcess;
trueFinished++;
}
}
curProcess++;
if(curProcess >= processNum) {
curProcess = curProcess % processNum;
//第一次遍历各个进程
if(flag == 0) {
temp = trueFinished;
temp0 = trueFinished;
}
//非第一次遍历各个进程
if(flag == 1) {
temp = trueFinished;
//遍历完后的trueFinish和这次遍历前的trueFinish相等
//即这次遍历完分配完成的进程数没有增加,说明系统剩余
//的资源已经不能满足任意未分配的进程了,即系统进入不安全状态
if(temp == temp0) {
break; //退出while循环
}else {
temp0 = temp;
}
}
flag = 1;
}
temp = trueFinished;
}
free(Work);
//完成分配的进程数等于内存进程数,即系统出于安全状态
if(trueFinished == processNum)
return true;
else //系统处于不安全状态
return false;
}
//打印当前资源分配表
void show() {
printf("----------------------------当前资源分配表----------------------------\n");
printf("各资源剩余:");
for(int i = 0; i < resourcesNum; i++) {
printf("%d ", Available[i]);
}
printf("\n");
printf("PID\t\t Max\t\t\t Allocation\t\t Need\n");
for(int i = 0; i < processNum; i++) {
printf("P%d\t\t ", i);
for(int j = 0; j < resourcesNum; j++) {
printf("%d ", Max[i][j]);
}
printf("\t\t\t ");
for(int j = 0; j < resourcesNum; j++) {
printf("%d ", Allocation[i][j]);
}
printf("\t\t\t ");
for(int j = 0; j < resourcesNum; j++) {
printf("%d ", Need[i][j]);
}
printf("\n");
}
printf("----------------------------------------------------------------------\n");
printf("\n");
}
int main(int argc, char* argv[])
{
printf("-------------进行系统资源初始化过程-------------\n\n");
FILE *fp = NULL;
//printf("%s\n", argv[1]);
fp = fopen(argv[1],"r");
printf("---->正在从文件data中读取数据···\n");
int flag1 = 1; //记录文件读取成功与否
init(argv, &flag1, fp);
if(flag1 == 0) {
printf("---->读取数据失败!\n\n");
return 0;
}
printf("---->读取数据完成!\n");
printf("\n-----------------系统初始化完成-----------------\n\n");
printf("\n系统安全情况分析\n");
printf("-----------------------------------当前时刻的安全序列表-----------------------------------\n");
printf("PID\t\t Work\t\t Need\t\t Allocation\t\t Work + Allocation\n");
if(isSafe()) {
printf("------------------------------------------------------------------------------------------\n");
printf("当前系统处于安全状态,其中一个安全序列为:");
for(int i = 0; i < processNum; i++) {
printf("P%d",safeSequence[i]);
if(i != processNum - 1)
printf(" -> ");
}
printf("\n");
}else {
printf("------------------------------------------------------------------------------------------\n");
printf("当前系统已处于不安全状态!\n");
//释放用malloc动态分配的内存,防止内存泄露
free(Allocation);
free(Max);
free(Need);
free(Available);
free(Finish);
free(safeSequence);
return 0;
}
printf("\n");
show(); //打印当前资源分配表
while(true) {
//printf("\n\n是否继续为进程分配资源?(1:是 0:否):");
//int flag;
//scanf("%d", &flag);
int flag;
fpos_t home; //记录当前行首位置
fgetpos(fp, &home); //将文件fp的当前读写位置保存到home中
int temp;
if(fscanf(fp, "%d", &temp) != EOF) { //判断当前文件指针是否指向末尾,注意这里文件指针会前进
flag = 1;
} else {
flag = 0;
}
//回退文件指针,回到行首
fsetpos(fp,&home);
if(flag) { //继续分配资源
printf("\n\n单击回车键继续为进程分配资源");
getchar();
int curProcess; //分配的进程号
Request = (int*)malloc(resourcesNum * sizeof(int)); //分配请求资源数组大小
fscanf(fp, "%d", &curProcess);
printf("从data文件中读取分配资源的进程号:%d\n", curProcess);
printf("从data文件中读取分配给 P%d 的各资源数:", curProcess);
for(int i = 0; i < resourcesNum; i++) {
fscanf(fp, "%d", &Request[i]);
printf("%d ", Request[i]);
}
printf("\n");
int count = 0; //记录curProcess请求的各资源小于其需要(Need)资源的个数
int count2 = 0; //记录curProcess请求的各资源小于系统剩余(Available)资源的个数
for(int i = 0; i < resourcesNum; i++) {
if(Request[i] <= Need[curProcess][i]) {
count++;
} else {
printf("\nERROR!请求的资源数大于需要的资源数!\n\n");
break;
}
}
if(count == resourcesNum) {
for(int i = 0; i < resourcesNum; i++) {
if(Request[i] <= Available[i]) {
count2++;
}
else {
printf("\n资源不足,等待其它进程释放资源中!\n\n");
break;
}
}
}
if(count2 == resourcesNum) {
//尝试为该进程分配其请求的资源
for(int i = 0; i < resourcesNum; i++) {
Available[i] -= Request[i];
Allocation[curProcess][i] += Request[i];
Need[curProcess][i] -= Request[i];
}
printf("\n系统安全情况分析\n");
printf("-----------------------------------当前时刻的安全序列表-----------------------------------\n");
printf("PID\t\t Work\t\t Need\t\t Allocation\t\t Work + Allocation\n");
if(isSafe()) {
printf("------------------------------------------------------------------------------------------\n");
printf("资源分配成功!安全序列为:");
for(int i = 0; i < processNum; i++) {
printf("P%d",safeSequence[i]);
if(i != processNum - 1)
printf(" -> ");
}
printf("\n\n");
show();
}else {
printf("------------------------------------------------------------------------------------------\n");
printf("资源分配失败!若分配会导致系统进入不安全状态!\n\n");
//回收尝试分配的资源
for(int i = 0; i < resourcesNum; i++) {
Available[i] += Request[i];
Allocation[curProcess][i] -= Request[i];
Need[curProcess][i] += Request[i];
}
}
}
}else {
//释放用malloc动态分配的内存,防止内存泄露
free(Allocation);
free(Max);
free(Need);
free(Available);
free(Finish);
free(safeSequence);
return 0;
}
}
//释放用malloc动态分配的内存,防止内存泄露
free(Allocation);
free(Max);
free(Need);
free(Available);
free(Finish);
free(safeSequence);
return 0;
}
注:实验中所有的数据均从data文件中获取,data文件与banker.c文件放在同一个文件夹中。
测试用例一(实验要求的数据)



测试用例二 (自己另外加的一组数据)




测试用例三(自己另外加的一组数据):测试系统刚开始就已经处于不安全状态的情况


本次实验要求输入数据从文本文件中读出,不从键盘录入,且要求通过命令行参数指定文件,如: ./banker ./data运行。因此需要在程序目录下建立data文件,然后在main函数中添加参数:int main(int argc, char* argv[]) ,其中argc记录参数的个数,argv数组记录在命令行中输入的参数,这里我们运行程序时在命令行中输入的是两个参数:./banker和./data,因此数组argv中存放的就是这两个字符串,argv[1]就是data文件的路径,通过文件指针指向data文件:FILE *fp = fopen(argv[1],“r”); 然后根据data文件中给的数据的顺序依次读取赋给给进程数、系统资源种数、资源最大数向量、已分配资源向量、最大资源需求量向量和资源请求向量赋值,进行系统的初始化。
实验还要求程序可支持不同个数的进程和不同个数的资源;因此程序中的各种数据结构采用数组形式,用malloc实现动态分配大小,根据进程数(processNum)和资源数(resourcesNum)动态分配各数组空间大小,具体可见代码中的初始化函数:void init()。
程序实现:首先从data文件中读取数据对各数据结构进行初始化,若读取失败(命令行参数指定的文件在程序目录下不存在),提示读取失败,结束程序;读取成功,则对刚初始化的系统进行安全性检测,打印安全序列表,若系统处于不安全状态,安全序列表打印出来的进程数就会小于总进程数,并提示系统处于不安全状态,然后结束程序;处于安全状态则列出一个安全序列,并列出当前的资源分配表(包括系统各资源剩余、各进程的Max、Allocation和Need),然后根据当前文件是否读到文件尾(即data文件中有无资源请求),若无则结束程序,有则利用getchar()并提示按下回车进行资源分配,若进程请求的资源大于其需要的最大资源,则提示错误信息;若进程请求的资源大于系统剩余的资源,则提示“资源不足,等待其他进程释放资源“;否则系统尝试分配给该进程申请的资源,然后调用安全性检测isSafe()函数,若系统处于不安全状态,则提示“分配失败,若分配系统将处于不安全状态”,并将尝试分配的资源进行回收;若系统处于安全状态,则将分配后的安全序列表(包括一个安全序列)和当前资源分配表打印出来,然后继续判断文件是否读到文件尾,通过getchar()实现每次按下回车进行一个进程的资源分配。
思考:为什么说找到了安全序列,就能够保证这个此次分配是安全的?safe的本质是什么?
这种安全之说,实际上是建立在一种假设之上的。其实,在实际的执行过程中,我们根本无法确定各进程是否会尽力去申请其声明的最大数额的资源,这是其一;其二,这种序列,也只是一种假设,是我们自己找出来的一种可能的不会造成死锁的方案,进程实际的执行顺序是不可能与我们预测的完全一致的。进程何时停止?到底会申请多少资源?我们无从而知。所以,系统假定所有进程将最终试图获取其声明的最大资源并在之后马上终止,并释放资源。这是一个合理的假设,因为系统不会特意关注每个进程运行了多久。此外,如果一个进程终止前没有获取它能获取的最大数额的资源,也无伤大雅,这种情况对系统而言反而更容易处理。 基于这一假设,该算法通过尝试寻找一个理想的进程请求序列集合来决定是否安全,根据这个集合中的序列方案,每个进程能够获得的最大资源,之后结束,并把资源返还给系统。
附:银行家算法的验证数据文件data格式说明
验证数据:建立在程序目录下建立data文件,文件内容是:
5 3
10 5 7
0 0 1 0 7 5 3
1 2 0 0 3 2 2
2 3 0 2 9 0 2
3 2 1 1 2 2 2
4 0 0 2 4 3 3
1 1 0 2
4 3 3 0
0 0 2 0
第一行:5个进程,3种资源。
第二行:每种资源系统拥有的最大数量。
3-7行:第一列是进程号(按顺序排),2-4列是Allocation(资源请求)向量,5-7列是Max(最大资源需求量)向量。
8-10行:第一列是进程号,2-4列是Request(资源请求)向量。
运行程序,通过命令行参数指定文件,如: ./banker ./data运行。
电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。 准备工作: 1、U盘一个(尽量使用8G以上的U盘)。 2、一台正常联网可使用的电脑。 3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。 4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。 U盘启动盘制作步骤: 注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注
目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc
我有一个使用SeleniumWebdriver和Nokogiri的Ruby应用程序。我想选择一个类,然后对于那个类对应的每个div,我想根据div的内容执行一个Action。例如,我正在解析以下页面:https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=puppies这是一个搜索结果页面,我正在寻找描述中包含“Adoption”一词的第一个结果。因此机器人应该寻找带有className:"result"的div,对于每个检查它的.descriptiondiv是否包含单词“adoption
我正在我的Rails项目中安装Grape以构建RESTfulAPI。现在一些端点的操作需要身份验证,而另一些则不需要身份验证。例如,我有users端点,看起来像这样:moduleBackendmoduleV1classUsers现在如您所见,除了password/forget之外的所有操作都需要用户登录/验证。创建一个新的端点也没有意义,比如passwords并且只是删除password/forget从逻辑上讲,这个端点应该与用户资源。问题是Grapebefore过滤器没有像except,only这样的选项,我可以在其中说对某些操作应用过滤器。您通常如何干净利落地处理这种情况?
在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.
因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实
a=[3,4,7,8,3]b=[5,3,6,8,3]假设数组长度相同,是否有办法使用each或其他一些惯用方法从两个数组的每个元素中获取结果?不使用计数器?例如获取每个元素的乘积:[15,12,42,64,9](0..a.count-1).eachdo|i|太丑了...ruby1.9.3 最佳答案 使用Array.zip怎么样?:>>a=[3,4,7,8,3]=>[3,4,7,8,3]>>b=[5,3,6,8,3]=>[5,3,6,8,3]>>c=[]=>[]>>a.zip(b)do|i,j|c[[3,5],[4,3],[7,6],
我有一个非常简单的Controller来管理我的Rails应用程序中的静态页面:classPagesController我怎样才能让View模板返回它自己的名字,这样我就可以做这样的事情:#pricing.html.erb#-->"Pricing"感谢您的帮助。 最佳答案 4.3RoutingParametersTheparamshashwillalwayscontainthe:controllerand:actionkeys,butyoushouldusethemethodscontroller_nameandaction_nam