代码地址
说明:参照大佬的h5实现银行家算法,我在这用vue实现了一版,以下是大佬链接【操作系统--用JavaScript实现银行家算法_对着世界说你好-CSDN博客】向大佬致敬
以下是个人理解,若有不对的地方请指正
算法简介
银行家算法是最著名的死锁避免算法,其思想是:把操作系统视为银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求分配资源相当于用户向银行家贷款。操作系统按照银行家制定的规则为进程分配资源。进程运行之前先声明对各种资源的最大需求量,当进程在执行中继续申请资源时,先测试该进程已占用的资源数与木次申请的资源数之和是否超过该进程声明的最大需求量。若超过则拒绝分配资源,若未超过则再测试系统现存的资源能否满足该进程尚需的最大资源量,若能满足则按当前的申请量分配资源,否则也要推迟分配。
王道书截图
流程图
代码分析
所需数据(data中数据)
data() {
return {
num_process: '', //记录进程数
num_resource: '', //记录资源数
process: 1, // 当前进度
availableTitle: [], // 可利用资源数目
available: [], // 可利用资源数目
// isb_ok2: false, // 按钮是否可用
helpObjArr: [], // 辅助对象数组[{name:'',max:[],available:[],allocation:[],need:[]}]
fg: false, //更新Available标志
work: [], //资源可用数
work2: [], //用于记录每次进程调用的Work数
finish: [], //是否已完成
o: 0,
safe: [], //安全序列
safeStr: '', // 展示安全序列,不安全则提出警告
showTable2: false, //
request: [],//请求资源数
helpObjArr2: [],// 辅助对象数组[{name:'',work:[],need:[],allocation:[],work+allocation:[],finish:false}]
showSafeTable: false, // 是否展示安全表格,可得到安全序列则展示
}
},
进程和资源输入页
没啥好说的,通过这俩变量记录num_process,num_resource
点击确定按钮增加了校验,点击确定后进入第二阶段,process赋值为2
onClickOK() {
if(this.num_process && this.num_resource){
this.$confirm(`${this.num_process}个进程${this.num_resource}个资源`, {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.process = 2; // 隐藏初试页面,进入第二个步骤
}).catch(() => {
});
}else{
this.$message({
message: '请输入数字',
type: 'warning'
});
}
},
输入对应资源数目,进入process=3
生成第一个表格
页面
重点在于表格内容分配上,需要合并单元格,并且进程资源数目是根据所输入num_resource大小所决定的,行数则和num_process的大小息息相关,我这里采用了helpObjArr来存储表格内容
helpObjArr数据格式[{name:'',max:['','',''],available:['','',''],allocation:['','',''],need:['','','']}]
其中name是进程名称,以max为例:max数组中存储的是各个进程资源,如max[0]对应max中A资源数目
将表格内容划分为两部分:资源行和其余的行
<table border=1 cellspacing=1 width=80% style='text-align:center;border-collapse:collapse;border:1px solid #ccc;'>
<tr>
<td>资源</td>
<td :colspan='Number(num_resource)'>Max</td>
<td :colspan='Number(num_resource)'>Allocation</td>
<td :colspan='Number(num_resource)'>Need</td>
<td :colspan='Number(num_resource)'>Available</td>
</tr>
<tr v-for="(items,indexs) in helpObjArr" :key="indexs">
<td>{{items.name}}</td>
<td v-for="(item,index) in items.max" :key="'max'+index">
<input class= 'numtext' type="text" :value="item" @blur="tdInput('max',indexs,index,$event)">
</td>
<td v-for="(item,index) in items.allocation" :key="'allocation'+index">
<input class= 'numtext' type="text" :value="item" @blur="tdInput('allocation',indexs,index,$event)">
</td>
<td v-for="(item,index) in items.need" :key="'need'+index">
<input class= 'numtext' type="text" readonly :value="item">
</td>
<td v-for="(item,index) in items.available" :key="'available'+index">
<input class= 'numtext' type="text" readonly :value="item">
</td>
</tr>
</table>
生成helpObjArr的代码
for (let i=0;i<= this.num_process;i++) {
let arr = []
let maxArr = []
let availableArr = []
let allocationArr = []
let needArr = []
for (let ii=0;ii<this.num_resource;ii++) {
arr.push(String.fromCharCode(65+ii))
maxArr.push('')
availableArr.push('')
allocationArr.push('')
needArr.push('')
}
this.helpObjArr.push({
name: i==0?'进程':'P'+(i-1),
max: i==0?arr:maxArr,
available: i==0?arr:availableArr,
allocation: i==0?arr:allocationArr,
need: i==0?arr:needArr,
})
}
通过tdInput获取输入的内容
type包括max和allocation两种,indexs可以得到相关进程,index则可以知道是具体 那个资源
tdInput(type,indexs,index, e) {
this.helpObjArr[indexs][type][index] = Number(e.target.value) // 将输入的数据存入表格中,需注意存入的是数字类型
},
提交检查
求need矩阵
这里需要注意的是多层嵌套的数据,vue不会触发dom更新,需刷新才显示数据
根据need = max - allocation
// 得到并填充Need
getNeed() {
for (let item in this.helpObjArr) {
if(item>0) {
for(let i in this.helpObjArr[item].max){
this.helpObjArr[item].need[i] = this.helpObjArr[item].max[i] - this.helpObjArr[item].allocation[i]
}
}
}
// 触发刷新
this.$forceUpdate()
},
求available
可知available为所有资源数目-已分配的资源总数
for(let i=0;i<this.num_resource;i++){
for(let j=0;j<this.num_process;j++){
this.available[i] -= this.helpObjArr[j+1].allocation[i];
if(this.available[i]<0){
this.$message({
message: '请求失败!无可利用资源',
type: 'warning'
});
return false;
}
}
}
求work向量
work初始值等于available中的值,这里需注意不能直接令this.work=this.available,需要深拷贝
for(let j=0;j<this.num_resource;j++){
this.work[j]=this.available[j];
}
创建安全序列
创建二维数组work2,finish用于存储当前进程是否执行完毕,o和flag是辅助变量,用于判断当前进程是否执行完毕,safe则存储安全序列
//初始化work2
for(let i=0;i<(this.num_process+1);i++){
this.work2[i] = new Array();
}
for(let i=0;i<this.num_resource;i++){
this.work2[0][i] = this.work[i];
}
//初始化finish
for(let i=0;i<this.num_process;i++){
this.finish[i] = false;
}
this.o = 0;
//算法核心!!!
while(this.o < this.num_process){
this.flag = false;
for(let i = 0; i < this.num_process; i ++){
if(this.finish[i])
continue;
let j;
// 当所需资源大于当前工作向量内容则跳出循环
for( j = 0; j < this.num_resource; j ++){
if(this.helpObjArr[i+1].need[j] > this.work[j])
break;
}
if(j == this.num_resource){
this.flag = true;
this.safe[this.o] = i;
this.o++;
this.finish[i] = true;
for(let k = 0; k < this.num_resource; k ++){
this.work[k] += this.helpObjArr[i+1].allocation[k];
this.work2[this.o][k] = this.work[k];
}
}
}
if(!this.flag)
break;
}
输出安全序列
if(this.o == this.num_process){
this.safeStr = '该资源是安全的;安全序列为:'
for (let i=0;i<this.o;i++) {
this.safeStr += 'P'+this.safe[i]
if(i<this.o-1){
this.safeStr += '->'
}
}
this.showSafeTable = true // 展示安全表格
}else {
this.safeStr = '对不起,该资源状态不安全!'
return;
}
生成安全表格
<table v-if="showSafeTable" border=1 cellspacing=1 width=80% style='text-align:center;border-collapse:collapse;border-width:thin;border-style:solid;margin:0;'>
<tr>
<td>资源</td>
<td :colspan='Number(num_resource)'>Work</td>
<td :colspan='Number(num_resource)'>Need</td>
<td :colspan='Number(num_resource)'>Allocation</td>
<td :colspan='Number(num_resource)'>Work+Allocation</td>
<td>Finish</td>
</tr>
<tr>
<td>进程</td>
<td v-for="value in Number(num_resource)" :key="'Work'+value">{{String.fromCharCode((64+value))}}</td>
<td v-for="value in Number(num_resource)" :key="'Need'+value">{{String.fromCharCode((64+value))}}</td>
<td v-for="value in Number(num_resource)" :key="'Allocation'+value">{{String.fromCharCode((64+value))}}</td>
<td v-for="value in Number(num_resource)" :key="'Work+Allocation'+value">{{String.fromCharCode((64+value))}}</td>
<td></td>
</tr>
<tr v-for="(items,indexs) in helpObjArr2" :key="indexs">
<td>{{items.name}}</td>
<td v-for="(item,index) in items.work" :key="'work'+index">
<input class= 'numtext' type="text" readonly :value="item">
</td>
<td v-for="(item,index) in items.need" :key="'need'+index">
<input class= 'numtext' type="text" readonly :value="item">
</td>
<td v-for="(item,index) in items.allocation" :key="'allocation'+index">
<input class= 'numtext' type="text" readonly :value="item">
</td>
<td v-for="(item,index) in items.workAllocation" :key="'workAllocation'+index">
<input class= 'numtext' type="text" readonly :value="item">
</td>
<td>
<input class= 'numtext' type="text" readonly :value="items.finish">
</td>
</tr>
</table>
给安全表格赋值
for(let i=0;i<this.num_process;i++){
this.helpObjArr2[i] = {name:'P'+this.safe[i],work:[],need:[],allocation:[],workAllocation:[],finish:false}
// 填充安全表格
for(let j=0;j<this.num_resource;j++){
this.helpObjArr2[i].work.push(this.work2[i][j])
this.helpObjArr2[i].need.push(this.helpObjArr[parseInt(this.safe[i])+1].need[j]) // parseInt(this.safe[i])+1这里加一的原因,表格一中ABC那一行我加入了数组中,表格二把ABC单独分开了,没放进数组
this.helpObjArr2[i].allocation.push(this.helpObjArr[parseInt(this.safe[i])+1].allocation[j])
this.helpObjArr2[i].workAllocation.push(this.work2[i][j]+this.helpObjArr[parseInt(this.safe[i])+1].allocation[j])
this.helpObjArr2[i].finish=this.finish[this.safe[i]]
}
}
// 触发刷新
this.$forceUpdate()
请求资源
新请求资源,P1请求A资源3个,B资源4个
得到新序列
this.fg = true;
var v1 = parseInt(window.prompt("请输入第几个进程请求资源"));
if(isNaN(v1)){
this.$message({
message: '请输入数字!',
type: 'warning'
});
return;
}
if(v1>this.num_process){
this.$message({
message: '没有该进程!',
type: 'warning'
});
return;
}
for(let i=0;i<this.num_process;i++){
this.request[i] = new Array();
}
for(let j=0;j<this.num_resource;j++){
this.request[v1-1][j] = window.prompt("进程P"+(v1-1)+"请求资源"+String.fromCharCode((65+j))+"数量:");
console.log(this.request[v1-1][j],typeof(this.request[v1-1][j]))
if(isNaN(this.request[v1-1][j]) || this.request[v1-1][j]===''){
this.$message({
message: '请输入数字!',
type: 'warning'
});
return;
}
}
for(let j=0;j<this.num_resource;j++){
if(this.request[v1-1][j]>this.helpObjArr[v1].need[j]){
this.$message({
message: '请求资源数大于所需最大值,失败!',
type: 'warning'
});
return;
}else if(this.request[v1-1][j]>this.available[j]){
this.$message({
message: '请求资源数大于可利用资源量,请等待!',
type: 'warning'
});
return;
}else{
this.available[j] -= this.request[v1-1][j];
var v2 = parseInt(this.helpObjArr[v1].allocation[j]);
var v3 = parseInt(this.request[v1-1][j]);
this.helpObjArr[v1].allocation[j] = v2+v3;
this.helpObjArr[v1].need[j] -= this.request[v1-1][j];
}
}
this.ChickSequence();
this.PrintSequence("output2");