程序仍然存在问题,仅供参考
想要练习相关实例和原理,可参考其他文章。本文章主要展示如何用可视化界面进行银行家算法
目录
一、简介
银行家算法(Banker's Algorithm)是一个避免死锁(Deadlock)的著名算法,是由艾兹格·迪杰斯特拉在1965年为T.H.E系统设计的一种避免死锁产生的算法。它以银行借贷系统的分配策略为基础,判断并保证系统的安全运行。 [1]
二、算法原理
我们可以把操作系统看作是银行家,操作系统管理的资源相当于银行家管理的资金,进程向操作系统请求分配资源相当于用户向银行家贷款。
为保证资金的安全,银行家规定:
(1) 当一个顾客对资金的最大需求量不超过银行家现有的资金时就可接纳该顾客;
(2) 顾客可以分期贷款,但贷款的总数不能超过最大需求量;
(3) 当银行家现有的资金不能满足顾客尚需的贷款数额时,对顾客的贷款可推迟支付,但总能使顾客在有限的时间里得到贷款;
(4) 当顾客得到所需的全部资金后,一定能在有限的时间里归还所有的资金.
操作系统按照银行家制定的规则为进程分配资源,当进程首次申请资源时,要测试该进程对资源的最大需求量,如果系统现存的资源可以满足它的最大需求量则按当前的申请量分配资源,否则就推迟分配。当进程在执行中继续申请资源时,先测试该进程本次申请的资源数是否超过了该资源所剩余的总量。若超过则拒绝分配资源,若能满足则按当前的申请量分配资源,否则也要推迟分配。
三、代码实现
1.初始界面:
主要代码:
<h1>银行家算法</h1>
<div id="input">
请输入进程数:<input type="text" id="t_process" name="t_process"/>
<br >
请输入资源数:<input type="text" id="t_resource" name="t_resource" />
<br ><br > <br >
<input type="button" id="b_ok" value="确定" name="b_ok" onClick="onClickOK()" />
<br >
</div>
2.读取完进程数和资源数后会弹窗确认,然后输入各资源总数
主要代码如下
function onClickOK() {
num_process = parseInt(document.getElementById("t_process").value);
num_resource = parseInt(document.getElementById("t_resource").value);
alert(num_process + "个进程" + num_resource + "个资源");
for (i = 0; i < num_resource; i++) {
available[i] = window.prompt("第" + (i + 1) + "个资源总数:");
}
CreateTable();
document.getElementById("d_display").style.display = "";
}
3.输入完总资源数后会出现第一个表格需要用户填写相应数据,点击提交会出现第二个表格,同时输出安全序列
主要代码:
1'创建第一个表格
//动态创建表格(第一个表格)
function CreateTable() {
var tabletext = "";
tabletext = "</br>系统资源的总数依次是:";
for (i = 0; i < num_resource; i++) {
tabletext += " " + available[i] + " ";
}
tabletext += "<p><p/><hr/>";
tabletext += "请输入各个进程的最大需求数(Max)和已分配数(Allocation)</br>";
tabletext += "<table border='1' cellspacing='1' class='bd1''><tr><td>资源</td><td colspan=" + num_resource + ">Max</td><td colspan=" + num_resource + ">Allocation</td><td colspan=" + num_resource + ">Need</td><td colspan=" + num_resource + ">Available</td></tr>";
tabletext += "<tr>" + "<td>进程</td>";
for (i = 0; i < 4; i++) {
for (j = 0; j < num_resource; j++) {
tabletext += "<td>" + String.fromCharCode((65 + j)) + "</td>";
}
}
tabletext += "</tr>";
for (i = 0; i < num_process; i++) {
tabletext += "<tr><td>P" + i + "</td>";
for (j = 0; j < 4; j++) {
for (x = 0; x < num_resource; x++) {
tabletext += "<td class='numtd'><input type=text id=e" + i + j + x + " class= 'numtext'";
if (j == 2 || j == 3) {
tabletext += " readonly=\"readonly\" "
}
tabletext += "></td>";
}
}
tabletext += "</tr>";
}
tabletext += "</table>";
document.getElementById("d_table").innerHTML += tabletext;
}
2'计算Need和Available
//得到并填充Available
function GetAvailable(fg) {
//计算Available
if (!fg) {
for (i = 0; i < num_resource; i++) {
for (j = 0; j < num_process; j++) {
available[i] -= allocation[j][i];
if (available[i] < 0) {
alert("请求失败!无可利用资源");
return false;
}
}
}
}
else {
if (available[i] < 0) {
alert("请求失败!无可利用资源");
return false;
}
else { }
}
//填充Available
for (i = 0; i < num_resource; i++) {
document.getElementById("e" + 0 + "3" + i).value = available[i];
}
return true;
}
//得到并填充Need
function GetNeed() {
//计算各进程对个资源的需求量
for (i = 0; i < num_process; i++) {
need[i] = new Array();
for (j = 0; j < num_resource; j++) {
need[i][j] = max[i][j] - allocation[i][j];
}
}
//填充Need
for (i = 0; i < num_process; i++) {
for (j = 0; j < num_resource; j++) {
document.getElementById("e" + i + "2" + j).value = need[i][j];
}
}
}
//得到Work
function GetWork() {
for (j = 0; j < num_resource; j++) {
work[j] = available[j];
}
}
3'点击第二个按钮出现第二个表格同时对上述填充的数据进行安全序列的判断
html
<div id="d_display" style="display: none;">
<div class="d_table" id="d_table"></div>
<br ><br >
<input type="button" id="b_ok2" value="提交检查" name="b_ok2" onclick="onClickOK2()">
<div class="output" id="output"></div>
<div class="output" id="outputlist"></div>
<div class="output" id="output2"></div>
</div>
js
//点击第二个按钮
function onClickOK2() {
GetInfo();
ChickSequence();
PrintSequence("outputlist");
}
function GetInfo() {
//获取最大资源数
for (i = 0; i < num_process; i++) {
max[i] = new Array();
for (j = 0; j < num_resource; j++) {
max[i][j] = parseInt(document.getElementById("e" + i + "0" + j).value);
}
}
//获取已分配资源数
for (i = 0; i < num_process; i++) {
allocation[i] = new Array();
for (j = 0; j < num_resource; j++) {
allocation[i][j] = parseInt(document.getElementById("e" + i + "1" + j).value);
}
}
}
function ChickSequence()//检查安全序列
{
GetNeed();
GetAvailable(fg);
GetWork();
//初始化work2
for (i = 0; i < (num_process + 1); i++) {
work2[i] = new Array();
}
for (i = 0; i < num_resource; i++) {
work2[0][i] = work[i];
}
//初始化finish
for (i = 0; i < num_process; i++) {
finish[i] = false;
}
o = 0; // 初始化安全序列的索引为0
while (o < num_process) // 循环直到所有进程都被标记为完成
{
flag = false; // 初始化标志为假,用于判断是否找到符合条件的进程
for (i = 0; i < num_process; i++) // 遍历所有进程
{
if (finish[i]) // 如果进程已经完成,则跳过
continue;
for (j = 0; j < num_resource; j++) // 遍历所有资源
{
if (need[i][j] > work[j]) // 如果进程需要的资源大于系统当前可用资源,则跳出内层循环
break;
}
if (j == num_resource) // 如果内层循环正常结束,说明找到了符合条件的进程
{
flag = true; // 设置标志为真
safe[o] = i; // 将当前进程加入安全序列
o++; // 安全序列索引加1
finish[i] = true; // 标记当前进程为已完成
for (k = 0; k < num_resource; k++) // 更新系统可用资源
{
work[k] += allocation[i][k]; // 将已分配给进程的资源释放给系统
work2[o][k] = work[k]; // 记录每一步的系统可用资源情况
}
}
}
if (!flag) // 如果未找到符合条件的进程,说明系统不处于安全状态,跳出循环
break;
}
}
//输出安全序列
function PrintSequence(id) {
if (o == num_process) {
html = "<hr>该资源是安全的;安全序列为:";
for (i = 0; i < o; i++) {
html += "P" + safe[i];
if (i < o - 1)
html += "->";
}
}
else {
html = "<hr>对不起,该资源状态不安全!";
document.getElementById(id).innerHTML = html;
return;
}
document.getElementById(id).innerHTML = html;
chickSafeTable();
}
function chickSafeTable() {
var tabletext = "";
tabletext = "<table 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=" + num_resource + ">Work</td><td colspan=" + num_resource + ">Need</td colspan=" + num_resource + "><td colspan=" + num_resource + ">Allocation</td colspan=" + num_resource + "><td colspan=" + num_resource + ">Work+Allocation</td colspan=" + num_resource + "><td>Finish</td></tr>";
tabletext += "<tr>" + "<td>进程</td>";
for (i = 0; i < 4; i++) {
for (j = 0; j < num_resource; j++) {
tabletext += "<td>" + String.fromCharCode((65 + j)) + "</td>";
}
}
tabletext += "</tr>";
for (i = 0; i < num_process; i++) {
tabletext += "<tr><td>P" + safe[i] + "</td>";
for (j = 0; j < 5; j++) {
for (x = 0; x < num_resource; x++) {
if (j == 4 && x == 0) {
tabletext += "<td id=t" + i + j + x + " class='outtable'></td>";
break;
}
else {
tabletext += "<td id=t" + i + j + x + " class='outtable'></td>";
}
}
}
tabletext += "</tr>";
}
tabletext += "</table>";
document.getElementById("output2").innerHTML += tabletext;
updataOfSafeList();
}
//更新安全表格
function updataOfSafeList() {
//Work
for (i = 0; i < num_process; i++) {
for (j = 0; j < num_resource; j++) {
document.getElementById("t" + i + "0" + j).innerHTML = work2[i][j];
}
}
//Need
for (i = 0; i < num_process; i++) {
for (j = 0; j < num_resource; j++) {
document.getElementById("t" + i + "1" + j).innerHTML = need[parseInt(safe[i])][j];
}
}
//Allocation
for (i = 0; i < num_process; i++) {
for (j = 0; j < num_resource; j++) {
document.getElementById("t" + i + "2" + j).innerHTML = allocation[parseInt(safe[i])][j];
}
}
//Work+Allocation
for (i = 0; i < num_process; i++) {
for (j = 0; j < num_resource; j++) {
document.getElementById("t" + i + "3" + j).innerHTML = work2[i][j] + allocation[safe[i]][j];
}
}
//Finish
for (i = 0; i < num_process; i++) {
document.getElementById("t" + i + "4" + "0").innerHTML = finish[safe[i]];
}
}
四、最终结果以及完整代码
完整代码
目录:
html代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="css/bank.css">
</head>
<body>
<h1>银行家算法</h1>
<div id="input">
请输入进程数:<input type="text" id="t_process" name="t_process"/>
<br >
请输入资源数:<input type="text" id="t_resource" name="t_resource" />
<br ><br > <br >
<input type="button" id="b_ok" value="确定" name="b_ok" onClick="onClickOK()" />
<br >
</div>
<div id="d_display" style="display: none;">
<div class="d_table" id="d_table"></div>
<br ><br >
<input type="button" id="b_ok2" value="提交检查" name="b_ok2" onclick="onClickOK2()">
<div class="output" id="output"></div>
<div class="output" id="outputlist"></div>
<div class="output" id="output2"></div>
</div>
<script src="js/banker.js"></script>
</body>
</html>
css代码:
.bd1{
table-layout:fixed;
width: 800px;
text-align: center;
overflow:hidden;
border: 1px solid;
}
.numtd{
width:15px;
}
js代码:
var num_process; //记录进程数
var num_resource;//记录资源数
var max = new Array();//最大资源数
var need = new Array();//资源需求数
var work = new Array();//资源可用数
var work2 = new Array();//用于记录每次进程调用的Work数
var available = new Array();//可利用资源数
var allocation = new Array();//已分配资源
var request = new Array();//请求资源数
var finish = new Array();//是否已完成
var safe = new Array();//安全序列
var fg = false; //更新Available标志
var o = 0;
//动态创建表格(第一个表格)
function CreateTable() {
var tabletext = "";
tabletext = "</br>系统资源的总数依次是:";
for (i = 0; i < num_resource; i++) {
tabletext += " " + available[i] + " ";
}
tabletext += "<p><p/><hr/>";
tabletext += "请输入各个进程的最大需求数(Max)和已分配数(Allocation)</br>";
tabletext += "<table border='1' cellspacing='1' class='bd1''><tr><td>资源</td><td colspan=" + num_resource + ">Max</td><td colspan=" + num_resource + ">Allocation</td><td colspan=" + num_resource + ">Need</td><td colspan=" + num_resource + ">Available</td></tr>";
tabletext += "<tr>" + "<td>进程</td>";
for (i = 0; i < 4; i++) {
for (j = 0; j < num_resource; j++) {
tabletext += "<td>" + String.fromCharCode((65 + j)) + "</td>";
}
}
tabletext += "</tr>";
for (i = 0; i < num_process; i++) {
tabletext += "<tr><td>P" + i + "</td>";
for (j = 0; j < 4; j++) {
for (x = 0; x < num_resource; x++) {
tabletext += "<td class='numtd'><input type=text id=e" + i + j + x + " class= 'numtext'";
if (j == 2 || j == 3) {
tabletext += " readonly=\"readonly\" "
}
tabletext += "></td>";
}
}
tabletext += "</tr>";
}
tabletext += "</table>";
document.getElementById("d_table").innerHTML += tabletext;
}
function onClickOK() {
num_process = parseInt(document.getElementById("t_process").value);
num_resource = parseInt(document.getElementById("t_resource").value);
alert(num_process + "个进程" + num_resource + "个资源");
for (i = 0; i < num_resource; i++) {
available[i] = window.prompt("第" + (i + 1) + "个资源总数:");
}
CreateTable();
document.getElementById("d_display").style.display = "";
}
//得到并填充Available
function GetAvailable(fg) {
//计算Available
if (!fg) {
for (i = 0; i < num_resource; i++) {
for (j = 0; j < num_process; j++) {
available[i] -= allocation[j][i];
if (available[i] < 0) {
alert("请求失败!无可利用资源");
return false;
}
}
}
}
else {
if (available[i] < 0) {
alert("请求失败!无可利用资源");
return false;
}
else { }
}
//填充Available
for (i = 0; i < num_resource; i++) {
document.getElementById("e" + 0 + "3" + i).value = available[i];
}
return true;
}
//得到并填充Need
function GetNeed() {
//计算各进程对个资源的需求量
for (i = 0; i < num_process; i++) {
need[i] = new Array();
for (j = 0; j < num_resource; j++) {
need[i][j] = max[i][j] - allocation[i][j];
}
}
//填充Need
for (i = 0; i < num_process; i++) {
for (j = 0; j < num_resource; j++) {
document.getElementById("e" + i + "2" + j).value = need[i][j];
}
}
}
//得到Work
function GetWork() {
for (j = 0; j < num_resource; j++) {
work[j] = available[j];
}
}
//点击第二个按钮
function onClickOK2() {
GetInfo();
ChickSequence();
PrintSequence("outputlist");
}
function GetInfo() {
//获取最大资源数
for (i = 0; i < num_process; i++) {
max[i] = new Array();
for (j = 0; j < num_resource; j++) {
max[i][j] = parseInt(document.getElementById("e" + i + "0" + j).value);
}
}
//获取已分配资源数
for (i = 0; i < num_process; i++) {
allocation[i] = new Array();
for (j = 0; j < num_resource; j++) {
allocation[i][j] = parseInt(document.getElementById("e" + i + "1" + j).value);
}
}
}
function ChickSequence()//检查安全序列
{
GetNeed();
GetAvailable(fg);
GetWork();
//初始化work2
for (i = 0; i < (num_process + 1); i++) {
work2[i] = new Array();
}
for (i = 0; i < num_resource; i++) {
work2[0][i] = work[i];
}
//初始化finish
for (i = 0; i < num_process; i++) {
finish[i] = false;
}
o = 0; // 初始化安全序列的索引为0
while (o < num_process) // 循环直到所有进程都被标记为完成
{
flag = false; // 初始化标志为假,用于判断是否找到符合条件的进程
for (i = 0; i < num_process; i++) // 遍历所有进程
{
if (finish[i]) // 如果进程已经完成,则跳过
continue;
for (j = 0; j < num_resource; j++) // 遍历所有资源
{
if (need[i][j] > work[j]) // 如果进程需要的资源大于系统当前可用资源,则跳出内层循环
break;
}
if (j == num_resource) // 如果内层循环正常结束,说明找到了符合条件的进程
{
flag = true; // 设置标志为真
safe[o] = i; // 将当前进程加入安全序列
o++; // 安全序列索引加1
finish[i] = true; // 标记当前进程为已完成
for (k = 0; k < num_resource; k++) // 更新系统可用资源
{
work[k] += allocation[i][k]; // 将已分配给进程的资源释放给系统
work2[o][k] = work[k]; // 记录每一步的系统可用资源情况
}
}
}
if (!flag) // 如果未找到符合条件的进程,说明系统不处于安全状态,跳出循环
break;
}
}
//输出安全序列
function PrintSequence(id) {
if (o == num_process) {
html = "<hr>该资源是安全的;安全序列为:";
for (i = 0; i < o; i++) {
html += "P" + safe[i];
if (i < o - 1)
html += "->";
}
}
else {
html = "<hr>对不起,该资源状态不安全!";
document.getElementById(id).innerHTML = html;
return;
}
document.getElementById(id).innerHTML = html;
chickSafeTable();
}
function chickSafeTable() {
var tabletext = "";
tabletext = "<table 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=" + num_resource + ">Work</td><td colspan=" + num_resource + ">Need</td colspan=" + num_resource + "><td colspan=" + num_resource + ">Allocation</td colspan=" + num_resource + "><td colspan=" + num_resource + ">Work+Allocation</td colspan=" + num_resource + "><td>Finish</td></tr>";
tabletext += "<tr>" + "<td>进程</td>";
for (i = 0; i < 4; i++) {
for (j = 0; j < num_resource; j++) {
tabletext += "<td>" + String.fromCharCode((65 + j)) + "</td>";
}
}
tabletext += "</tr>";
for (i = 0; i < num_process; i++) {
tabletext += "<tr><td>P" + safe[i] + "</td>";
for (j = 0; j < 5; j++) {
for (x = 0; x < num_resource; x++) {
if (j == 4 && x == 0) {
tabletext += "<td id=t" + i + j + x + " class='outtable'></td>";
break;
}
else {
tabletext += "<td id=t" + i + j + x + " class='outtable'></td>";
}
}
}
tabletext += "</tr>";
}
tabletext += "</table>";
document.getElementById("output2").innerHTML += tabletext;
updataOfSafeList();
}
//更新安全表格
function updataOfSafeList() {
//Work
for (i = 0; i < num_process; i++) {
for (j = 0; j < num_resource; j++) {
document.getElementById("t" + i + "0" + j).innerHTML = work2[i][j];
}
}
//Need
for (i = 0; i < num_process; i++) {
for (j = 0; j < num_resource; j++) {
document.getElementById("t" + i + "1" + j).innerHTML = need[parseInt(safe[i])][j];
}
}
//Allocation
for (i = 0; i < num_process; i++) {
for (j = 0; j < num_resource; j++) {
document.getElementById("t" + i + "2" + j).innerHTML = allocation[parseInt(safe[i])][j];
}
}
//Work+Allocation
for (i = 0; i < num_process; i++) {
for (j = 0; j < num_resource; j++) {
document.getElementById("t" + i + "3" + j).innerHTML = work2[i][j] + allocation[safe[i]][j];
}
}
//Finish
for (i = 0; i < num_process; i++) {
document.getElementById("t" + i + "4" + "0").innerHTML = finish[safe[i]];
}
}