皮卡丘忠实粉丝之Web实现操作系统实验(进程调度+存储管理+死锁避免银行家算法)

**皮卡皮卡丘~~~~~~**

进程调度

目的和要求

编写并调试一个模拟的进程调度程序,采用“最高优先数优先”调度算法对五个进程进行调度,以加深对进程的概念及进程调度算法的理解。

内容与步骤

设计一个有 N 个进程共行的进程调度程序。
**进程调度算法:**采用最高优先数优先的调度算法(即把处理机分配给优先数最高的进程)和先来先服务算法。每个进程有一个进程控制块( PCB)表示。进程控制块可以包含如下信息:进程名、优先数、到达时间、需要运行时间、已用 CPU 时间、进程状态等等。进程的优先数及需要的运行时间可以事先人为地指定(也可以由随机数产生),进程的到达时间为进程输入的时间,进程的运行时间以时间片为单位进行计算。每个进程的状态可以是就绪 W(Wait)、运行 R(Run)、或完成 F(Finish)三种状态之一(这是编程用到的三个模拟状态,并非进程的三基态)。就绪进程获得 CPU 后都只能运行一个时间片,用
已占用 CPU 时间加 1 来表示。如果运行一个时间片后,进程的已占用 CPU 时间已达到所需要的运行时间,则撤消该进程,如果运行一个时间片后进程的已占用 CPU 时间还未达所需要的运行时间,也就是进程还需要继续运行,此时应将进程的优先数减 1(即降低一级),然后把它插入就绪队列等待 CPU。每进行一次调度程序都打印一次运行进程、就绪队列、以及各个进程的 PCB,以便进行检查。重复以上过程,直到所要进程都完成为止。
调度算法的流程图如下 :
在这里插入图片描述
HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<style>
    .hid{
        display: none;
    }
    .appear{
        display: block;
    }
    span{
        margin-left: 50px;
    }
    .name{
        width: 70px;
        margin-left: 40px;
    }
    .super{
        width: 70px;
        margin-left: 30px;
    }
    .totaltime{
        width: 70px;
        margin-left: 30px;
    }
    .ok{
        margin-top: 30px;
    }
    #Waiting span,#Running span{
        margin-right: 40px;
    }
    .im-com{
        width:600px;
        height:350px;
        background:url(https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1558862265029&di=844ed2dec44eb9014a3450e13e3bbb7c&imgtype=0&src=http%3A%2F%2Fs10.sinaimg.cn%2Fmiddle%2F00378002g7a90910f4dc9%26690) no-repeat top left scroll;
        background-size:cover;
    }
    p{
        color:mediumpurple;
        font-family: STXingkai;
    }
    input{
        text-align: center;
        border-radius: 10px;
        background: transparent;

    }

</style>
<style type="text/css">
    #sure,#ok,#biggest{width: 50px;height: 50px;border-radius: 50%;border: none}
    /* border-radius */
</style>

<body>
<div class="im-com">
    <h1 align="center"><font color="#ffc0cb">进程调度</font></h1>
<div id="super" style="text-align:center; vertical-align:middle;">
    <big>
    <div id="box1">
        <p align="center">请输入进程号个数</p>
        <input    type="text" id="number"  title="num"/>
        <button  type="button" id="sure" style="background:skyblue">sure</button>
   </div>
    </big>
</div>

    <div id="box2" class="hid">
        <p align="center">请输入进程信息</p>
        <p>
            <span>进程名</span>
            <span>进程优先级</span>
            <span>进程运行时间</span>
        </p>
        <div id="input"></div>
        <button type="button" id="ok" class="ok" style="background:skyblue;margin-left: 140px">sure</button>
    </div>




    <div id="resultbox" class="hid">
        <p align="center">programming result</p>
        <p align="center">当前运行进程</p>
        <span>进程名</span><span>程序状态</span><span>优先级</span><span>需要时长</span><span>已运行时长</span>
        <div id="Running">
            当前没有运行中的队列
        </div>
        <p align="center">就绪队列</p>
        <span>进程名</span><span>程序状态</span><span>优先级</span><span>需要时长</span><span>已用时间</span>
        <div id="Waiting">

        </div>
        <br /><br />
        <button type="button" id="biggest" style="background:skyblue;margin-left: 174px">最高优先数优先</button>
    </div>
</div>

<script type="text/javascript" src="jincheng.js"></script>
</body>
</html>

JS代码

charset='utf-8';
console.log("*********  js   ***********");

let num_inp = document.getElementById("number");
let num;
let input=document.getElementById("input");
let btn = document.getElementById("sure");
let ready = [];
let ok = document.getElementsByClassName("ok")[0];
let biggest = document.getElementById("biggest");
let Running = document.getElementById("Running");
let Waiting = document.getElementById("Waiting");

let box1 = document.getElementById("box1"),
    box2 = document.getElementById("box2"),
    resultbox = document.getElementById("resultbox");

btn.onclick = function(){//创建输入框
    num = num_inp.value;
    console.log(num);
    let INNER="";
    for(let i=0;i<num;i++){
        INNER +=`<div>
                    <input title="inf" class="name">
                    <input title="inf" class="super">
                    <input title="inf" class="totaltime">
                  </div>`;
    }
    input.innerHTML = INNER;
    box1.className = "hid";
    box2.classList.remove("hid");
};

ok.onclick = function () {//获取输入框的值

    let names=document.getElementsByClassName("name"),
        supers = document.getElementsByClassName("super"),
        totaltimes=document.getElementsByClassName("totaltime");

    for(let i=0;i<num;i++){
        let m = {
            name: names[i].value,
            super: supers[i].value,
            state: "w",
            ntime: totaltimes[i].value,
            rtime: 0
        };
        ready.push(m);
    }
    // Sort();
    console.log(ready);
    let W = "";
    for (let i = 0; i < ready.length; i++) {
        W+=`
            <p>
                <span>`+ready[i].name+`</span><span>Waiting</span><span>`+ready[i].super+`</span><span>`+ready[i].ntime+`</span><span>`+ready[i].rtime+`</span>
            </p>
        `;
    }
    Waiting.innerHTML = W;
    box2.className = "hid";
    resultbox.classList.remove("hid");
};


function Sort() {
    function compare(property){
        return function(a,b){
            let value1 = a[property];
            let value2 = b[property];
            return value2 - value1;
        }
    }
    ready.sort(compare('super'));
    console.log(ready);
}

biggest.onclick = function() {//点击下一步
    if (ready.length===0){
        alert("全部完成");
        return 0;
    } else {
        RunSuper();
    }
};

function RunSuper() {
    ready[0].state="running";
    ready[0].super--;
    ready[0].rtime++;
    disp();
    let t = ready[0];
    ready.splice(0,1);
    if(t.rtime != t.ntime){
        ready.push(t);
    }
}

function disp() {
    let R = `<p>
                <span>`+ready[0].name+`</span><span>Running</span><span>`+ready[0].super+`</span><span>`+ready[0].ntime+`</span><span>`+ready[0].rtime+`</span>
            </p>`;
    Running.innerHTML = R;
    let W = "";
    for (let i = 0; i < ready.length - 1; i++) {
        W+=`
            <p>
                <span>`+ready[i+1].name+`</span><span>Waiting</span><span>`+ready[i+1].super+`</span><span>`+ready[i+1].ntime+`</span><span>`+ready[i+1].rtime+`</span>
            </p>
        `;
    }
    Waiting.innerHTML = W;
}

运行结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

问题及心得

通过此次实验,了解了进程调度相关的知识,这次实验采用的是最高优先数优先算法,即把 CPU 分配给就绪队列中优先数最高的进程,而其中所用的静态优先数是在创建进程时确定的,并在整个进程运行期间不再改变。所选用的图形界面是用web所显示出来,通过网页w3school自学了HTML的相关知识,懂得了相关的基本操作,编写了js代码,逻辑上面还有待提高,界面还需要进一步地优化。

C语言实现代码

#include"stdio.h"
#include<stdlib.h>
#include<conio.h>
#define getpch(type) (type*)malloc(sizeof(type))
#define NULL 0

struct pcb //定义进程控制块pcb
{
	char name[10];
    char state;
	int super;
	int ntime;
	int rtime;
	struct pcb *link;
}*ready=NULL,*p;

typedef struct pcb PCB;
sort()//建立对进程进行优先级排列函数
{
	PCB *first ,*second;
	int insert=0;
	if((ready==NULL)||((p->super)>(ready->super)))//优先级最大者,插入队首
	{
		p->link=ready;
		ready=p;}
	else
	{
		first=ready;
		second=first->link;
		while(second!=NULL)
		{
			if((p->super)>(second->super))//若插入进程比当前进程优先级大
			{/*插入到当前进程前面*/
				p->link=second;
				first->link=p;
				second=NULL;
				insert=1;}
			else //插入进程优先级最低,则插入到队尾
			{
				first=first->link;
				second=second->link;}
		}//while结束
		if(insert==0)
			first->link=p;
	}
}

input() //建立进程控制块函数
{
	int i,num;
//	clrscr();//清屏
	printf("\n 请输入进程号个数?");
	scanf("%d",&num);
	for(i=0;i<num;i++)
	{
		printf("\n 进程号No.%d:\n",i);
		p=getpch(PCB);
		printf("\n 输入进程名:");
		scanf("%s",p->name);
		printf("\n 输入进程优先数:");
		scanf("%d",&p->super);
		printf("\n 输入进程运行时间:");
		scanf("%d",&p->ntime);
		printf("\n");
		p->rtime=0;
		p->state='w';
		p->link=NULL;
		sort(); //调用sort函数
	}
}

int space()
{
	int l=0;
	PCB *pr=ready;
	while(pr!=NULL)
	{
		l++;
		pr=pr->link;
	}
	return(l);
}

disp(PCB *pr) //建立进程显示函数,用于显示当前进程
{
	printf("\n qname \t state \t super \t ndtime \t runtime \n");
	printf("|%s\t",pr->name);
	printf("|%c\t",pr->state);
	printf("|%d\t",pr->super);
	printf("|%d\t",pr->ntime);
	printf("|%d\t",pr->rtime);
	printf("\n");
}

check() //建立进程查看函数
{
	PCB *pr;
	printf("\n ****当前正在运行的进程是:%s",p->name); //显示当前运行的进程
	disp(p);
	pr=ready;
	printf("\n ****当前就绪队列状态为:\n"); //显示就绪队列的状态
	while(pr!=NULL)
	{
		disp(pr);
		pr=pr->link;

	}
}

destroy() //建立进程撤销函数
{
	printf("\n 进程[%s] 已完成.\n",p->name);
	free(p);
}

running() //建立进程就绪函数
{
	(p->rtime)++;
	if(p->rtime==p->ntime)
		destroy(); //调用destroy函数
	else
	{
		(p->super)--;
		p->state='w';
		sort();  
	}
}

main()
{
	int len,h=0;
	char ch;
	input();
	len=space();
	while((len!=0)&&(ready!=NULL))
	{
		ch=getchar();
		h++;
		printf("\n The execute number:%d \n",h);
		p=ready;
		ready=p->link;
		p->link=NULL;
		p->state='R';
		check();
		running();
		printf("\n 按任一键继续……");
		ch=getchar();
	}
	printf("\n\n 进程已经完成. \n");
	ch=getchar();
	return 0;
}

存储管理

目的和要求

目的
1:通过编写和调试存储管理的模拟程序以加深对存储管理方案的理解,熟悉虚存管理的各种页面淘汰算法。
2:通过编写和调试地址转换过程的模拟程序以加强对地址转换过程的了解。
要求
设计一个固定式分区分配的存储管理方案,并模拟实现分区的分配和回收过程。可以假定每个作业都是批处理作业,并且不允许动态申请内存。为实现分区的分配和回收,可以设定一个分区说明表,按照表中的有关信息进行分配,并根据分区的分配和回收情况修改表。

内容与步骤

假定每个作业都是批处理作业,并且不允许动态申请内存。为实现分区的分配和回收,设定一个分区说明表,按照表中的有关信息进行分配,并根据分区的分配和回收情况修改该表。

HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        h1{
            position: absolute;
            right: 288px;
            top: 81px;
            width: 10px;
            font-size: 44px;
        }
        p{
            color:purple;
            font-family: STXingkai;
        }
        span{
            margin-left: 35px;
            margin-top: 100px;
        }
        #showcontent span{
            margin-right: 35px;
        }
        #alocatebox,#showbox,#recylebox{
            padding: 50px;
            border: 1px;
            width: 600px;
            margin: 40px;
        }

        .im-com{
            /*width:800px;*/
            height:850px;
            background:url(https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1558862265029&di=844ed2dec44eb9014a3450e13e3bbb7c&imgtype=0&src=http%3A%2F%2Fs10.sinaimg.cn%2Fmiddle%2F00378002g7a90910f4dc9%26690) no-repeat top left scroll;
            background-size:cover;
            background-position-y: -20px;
        //margin:40px;
        }
        .hid{
            display: none;
        }
        input{
            text-align: center;
            -webkit-border-radius: 10px;
            -moz-border-radius: 10px;
            border-radius: 10px;
        }
    </style>
</head>
<body>
<h1 align="center"><font color="#87ceeb">存储管理</font></h1>
<div class="im-com">
    <div id="showbox" style="text-align:center; vertical-align:middle;">
        <p>分区</p>
        <p>
            <span>编号</span><span>大小</span><span>状态</span><span>运行进程ID</span>
        </p>
        <p id="showcontent">

        </p>
    </div>

    <div id="alocatebox" style="text-align:center; vertical-align:middle;">
        <big>
        <p>请输入作业号</p>
        <input type="text" title="sdf" id="num">
        <p>请输入作业内存大小</p>
        <input type="text" title="sd" id="size"><br/>
        <button type="button" id="sure1" style="margin-top: 20px; border-radius: 10px; background: pink">sure</button>
        </big>
        <button id="start_recycle" type="button" title="sdf" style="display: block;margin-left: 265px; margin-top: 40px;border-radius: 10px; background: skyblue ">
            开始回收
        </button>
    </div>

    <div id="recyclebox" class="hid" style="margin-left:277px; margin-top:121px; vertical-align:middle;">
        <big>
        <p>请输入要释放的进程号</p>
        <input type="text"  title="dsf" id="rec_num">
        <button type="button" id="sure2">sure</button>
        </big>
    </div>
</div>


<script type="text/javascript" src="cunchu.js"></script>
</body>
</html>

JS代码

/*初始化*/
let cont = document.getElementById("showcontent");//展示的p盒子
let freeareas = [];//分区列表
for (let i = 1; i < 6; i++) {
    let area = {
        id: i,
        size: 100,
        state: "可分配",
        processid: 0
    }//固定分区,大小100,状态可分配,进程id为0表示没有进程
    freeareas.push(area);
}
function show() {
    cont.innerHTML = "";
    let t = "空闲";

    let con="";
    for (let i = 0; i < freeareas.length; i++) {
        t = freeareas[i].processid===0?"空闲":freeareas[i].processid;
        con = `
        <span>`+freeareas[i].id+`</span><span>`+freeareas[i].size+`</span><span>`+freeareas[i].state+`</span><span>`+t+`</span><br />
        `;
        console.log(con);
        cont.innerHTML += con;
    }

}
show();
//  结束初始化




//确定新建进程号并分配分区
//获取进程信息
let proid = document.getElementById("num"),
    size = document.getElementById("size");
//完成获取进程信息
//获取按钮
let sure1 = document.getElementById("sure1");
//完成获取按钮并绑定事件
sure1.onclick = function () {
    //顺序检查分区是否够用
    let sccess = false;
    for (let i=0;i<freeareas.length;i++){
        if (freeareas[i].state==="可分配"){
            if (freeareas[i].size >= size.value) {
                freeareas[i].state = "已分配";
                freeareas[i].processid = proid.value;
                sccess = true;
                break;
            }
            else {
                break;
            }
        }
    }
    if (!sccess) {
        alert("分配失败");
    }
    show();
};

//此功能完成


//回收内存
let recybtn = document.getElementById("sure2");
let recyid = document.getElementById("rec_num");

recybtn.onclick = function () {
    if (recyid.value===""){
        alert("请输入回收进程的id");
    }else {
        let success = false;
        for (let i = 0; i < freeareas.length; i++) {
            if (freeareas[i].processid === recyid.value) {
                success = true;
                freeareas[i].state = "可分配";
                freeareas[i].processid = 0;
            }
        }
        if (!success){
            alert("没有该进程");
        }
    }
    show();
};
let alocatebox = document.getElementById("alocatebox"),
    recycle_box = document.getElementById("recyclebox"),
    start_recycle = document.getElementById("start_recycle");

console.log(alocatebox);
start_recycle.onclick = function () {
    alocatebox.className = "hid";
    recycle_box.className = "";
};

运行结果

在这里插入图片描述
在这里插入图片描述

问题及心得

通过此次实验,了解了存储管理相关的知识,掌握了虚存管理的不同页面淘汰算法,同时加强对地址转换过程的了解,此次实验是设计一个固定式分区分配的存储管理方案,模拟实现分区的分配和回收过程,掌握了分区分配的基本原理与流程,并用web将结果显示出来,js的代码还需要进一步的优化,显示的布局与逻辑还需要进一步地改善。

C语言实现代码

#include<stdio.h>
#include<dos.h>
#include<stdlib.h>
#include<conio.h>
#include<iostream.h>

#define n 10 //假定系统允许的最大作业数为n,假定模拟实验中n的值为10
#define m 10 //假定系统允许的空闲区表最大为m,假定模拟实验中m的值为10
#define minisize 100 //空闲分区被分配时,如果分配后剩余空间小于minisize,则将该空闲分区全部分配,若大于minisize,则切割分配

struct
{
	float address;//已分配分区起始地址
	float length;//已分配分区长度,单位为字节
	int flag;//已分配区表登记栏标志,用0表示空栏目
}used_table[n];//已分配区表

struct
{
	float address;//空闲区起始地址
	float length;//空闲区长度,单位为字节
	int flag;//空闲区表登记栏标志,用0表示空栏目,用1表示未分配
}free_table[m];//空闲区表

void allocate(char J,float xk)//给J作业,采用最佳分配算法分配xk大小的空间
{
	int i,k;
	float ad;
	k=-1;
	for(i=0;i<m;i++) //寻找空间大于xk的最小空闲区登记项k
		if(free_table[i].length>=xk && free_table[i].flag==1)
			if(k==-1 ||free_table[i].length<free_table[k].length)
				k=i;
			if(k==-1)
			{
				printf("无可用空闲区\n");
				return;
			}
			//找到可用空闲区,开始分配:若空闲区大小与要求分配的空间差小于minisize大小,则空闲区全部分配
			//若空闲区大小与要求分配的空间差大于minisize,则从空间区划出一部分分配
			if(free_table[k].length-xk<=minisize)
			{
				free_table[k].flag=0;
				ad=free_table[k].address;
				xk=free_table[k].length;
			}
			else
			{
				free_table[k].length=free_table[k].length-xk;
				ad=free_table[k].address+free_table[k].length;
			}
			//修改已分配区表
			i=0;
			while(used_table[i].flag!=0 && i<n) //寻找空表目
				i++;
			if(i>=n) //无表目可填写已分配分区
			{
				printf("无表目填写已分分区,错误\n");
				//修正空闲区表
				if(free_table[k].flag==0)
					//前面找的是整个空闲分区
					free_table[k].flag=1;
				else
				{ //前面找到的是某个空闲分区的一部分
					free_table[k].length=free_table[k].length+xk;
					return;
				}
			}
			else
			{//修改已分配表
				used_table[i].address=ad;
				used_table[i].length=xk;
				used_table[i].flag=J;
			}
			return;
}//主存分配函数结束

void reclaim(char J)//回收作业名为J的作业所占主存空间
{
	int i,k,j,s,t;
	float S,L;
	//寻找已分配表中对应登记项
	s=0;
	while((used_table[s].flag!=J || used_table[s].flag==0) && s<n)
		s++;
	if(s>=n) //在已分配表中找不到名字为J的作业
	{
		printf("找不到该作业\n");
		return;
	}
	//修改已分配表
	used_table[s].flag=0;
	//取得归还分区的起始地址S和长度L
	S=used_table[s].address;
	L=used_table[s].length;
	j=-1;
	k=-1;
	i=0;
	//寻找回收分区的空闲上下邻,上邻表目k,下邻表目j
	while(i<m && (j==-1 || k==-1))
	{
		if(free_table[i].flag==1)
		{
			if(free_table[i].address+free_table[i].length==S)
				k=i;//找到上邻
			if(free_table[i].address==S+L)
				j=i;//找到下邻
		}
		i++;
	}
	if(k!=-1)
		if(j!=-1)//上邻空闲区,下邻空闲区,三项合并
		{
			free_table[k].length=free_table[j].length+free_table[k].length+L;
			free_table[j].flag=0;
		}
		else//上邻空闲区,下邻非空闲区,与上邻合并
			free_table[k].length=free_table[k].length+L;
		else
			if(j!=-1)
				//上邻非空闲区,下邻为空闲区,与下邻合并
			{
				free_table[j].address=S;
				free_table[j].length=free_table[j].length+L;
			}
			else
				//上下邻均为非空闲区,回收区域直接填入
			{
				//在空闲区表中寻找空栏目
				t=0;
				while(free_table[t].flag==1 && t<m)
					t++;
				if(t>=m)//空闲区表满,回收空间失败,将已分配表复原
				{
					printf("主存空闲表没有空间,回收空间失败\n");
					used_table[s].flag=J;
					return;
				}
				free_table[t].address=S;
				free_table[t].length=L;
				free_table[t].flag=1;
			}
			return;
}//主存回收函数结束

int main()
{
	int i,a;
	float xk;
	char J;
	//空闲分区表初始化
	free_table[0].address=10240;//起始地址假定为10240
	free_table[0].length=10240;//长度假定为10240,即10k
	free_table[0].flag=1;//初始空闲区为一个整体空闲区

	for(i=1;i<n;i++)
		free_table[i].flag=0;//其余空闲分区表项未被使用
	//已分配表初始化
	for(i=0;i<n;i++)
		used_table[i].flag=0;//初始时均未分配
	while(1)
	{
		printf("选择功能项(0-退出,1-分配主存,2-回收主存,3-显示主存\n");
		printf("选择功能项(0-3):");
		scanf("%d",&a);
		switch(a)
		{
		case 0:exit(0);//a=0程序结束
		case 1://a=1分配主存空间
			printf("输入作业名 J 和作业所需长度 xk :");
			scanf("%*c%c%f",&J,&xk);
			allocate(J,xk);
			break;
		case 2://a=0回收主存空间
			printf("输入要回收分区的作业名");
			scanf("%*c%c",&J);
			reclaim(J);//回收主存空间
			break;
		case 3://a=3显示主存情况
			//输出空闲区表和已分配表的内容
			printf("输出空闲区表:\n 起始地址 分区长度 标志\n");
			for(i=0;i<m;i++)
				printf("%6.0f%9.0f%6d\n",free_table[i].address,free_table[i].length,free_table[i].flag);
			printf("按任意键,输出已分配区表\n");
			getch();
			printf("输出已分配区表:\n 起始地址 分区长度 标志\n");
			for(i=0;i<n;i++)
				if(used_table[i].flag!=0)
					printf("%6.0f%9.0f%6c\n",used_table[i].address,used_table[i].length,used_table[i].flag);
				else
					printf("%6.0f%9.0f%6d\n",used_table[i].address,used_table[i].length,used_table[i].flag);
			break;
		default:printf("没有该选项\n");
		}
	}
	return 1;
}

动态分区分配

#include<iostream>
using namespace std;
const int Max_length=640;//最大内存
int a,b;//记录算法编号,b记录操作编号
struct freearea//空闲区的结构体
{
	int ID;//分区号
	int size;//分区大小
	int address;//分区地址
	bool flag;//使用状态,0未占用,1为已占用
};

typedef struct DuNode//双向链表结点
{
	freearea data;//数据域
	DuNode *prior;//指针域
	DuNode *next;
}*DuLinkList;
DuLinkList m_rid=new DuNode,m_last=new DuNode;//双向链表收尾指针

void init()//空闲区队列初始化
{
	m_rid->prior=NULL;
	m_rid->next=m_last;
	m_last->prior=m_rid;
	m_last->next=NULL;
	m_rid->data.size=0;
	m_last->data.address=0;
	m_last->data.size=Max_length;
	m_last->data.ID=0;
	m_last->data.flag=0;//!!!
}

void show()
{
	DuNode *p=m_rid->next;//指向空闲区队列的首地址
	cout<<"+++++++++++++++++++++++++++++++++++++"<<endl;
	while(p)
	{
		cout<<"分区号:  ";
		if(p->data.ID==0)
			cout<<"FREE"<<endl;
		else
			cout<<p->data.ID<<endl;
		cout<<"分区起始地址:  "<<p->data.address<<endl;
		cout<<"分区大小:  "<<p->data.size<<endl;
		cout<<"分区状态:  ";
		if(p->data.flag)
			cout<<"已被占用"<<endl;
		else
			cout<<"空闲"<<endl;
		cout<<"-------------------------------------"<<endl;
		p=p->next;
	}
}

bool first_fit(int id,int m_size)//首次适应算法
{
	DuNode *p=m_rid->next;//指向空闲区队列的首地址
	DuLinkList fa=new DuNode;//新建一个空闲区并赋值
	//memset(fa,0,sizeof(DuNode));
	fa->data.ID=id;
	fa->data.size=m_size;
	fa->data.flag=1;//表示被占用
	while(p)//在空闲区列表中从低地址向高地址查找
	{
		if(p->data.size>=m_size && !p->data.flag)//找到大于等于所需的内存的空闲区
		{
			if(p->data.size==m_size)//刚好空闲区大小与所需大小相等
			{
				p->data.ID=id;
				p->data.flag=1;
				free(fa);//清空新创建的空闲区
				return true;
			}
			else if(p->data.size>m_size)//空闲区比所需内存大,则需要将多的内存放到回收处
			{
				fa->data.address=p->data.address;//将空闲区的前半部分分出去
				p->data.address+=m_size;
				p->data.size-=m_size;
				p->prior->next=fa;
				fa->next=p;
				fa->prior=p->prior;
				p->prior=fa;
				return true;
			}
		}
		p=p->next;
	}
	free(fa);//查找分配失败
	return false;
}

bool best_fit(int id,int m_size)//最佳适应算法,其中需要查找最佳的存放位置
{
	DuNode *p=m_rid->next;//指向空闲区队列的首地址
	DuNode *q=NULL;//存放最佳地址
	DuLinkList fa=new DuNode;//新建一个空闲区并赋值
	memset(fa,0,sizeof(DuNode));
	fa->data.ID=id;
	fa->data.size=m_size;
	fa->data.flag=1;//表示被占用
	int d=Max_length;//所需内存大小与空闲区大小之间的差值
	while(p)
	{
		if(p->data.size>=m_size && !p->data.flag)//找到大于等于所需的内存的空闲区
		{
			if(p->data.size-m_size<d)
			{
				q=p;
				d=q->data.size-m_size;
			}
		}
		p=p->next;
	}
	if(q==NULL)//查找分配失败
		return false;
	else
	{
		if(d==0)//刚好找到与所需内存大小一样的空闲区
		{
			p->data.ID=id;
			p->data.flag=1;
			free(fa);//清空新创建的空闲区
			return true;
		}
		else//空闲区比所需内存大,则需要将多的内存作为回收处理
		{
			fa->data.address=q->data.address;//将空闲区的前半部分分出去
			q->data.address+=m_size;
			q->data.size-=m_size;
			q->prior->next=fa;
			fa->next=q;
			q->prior=fa;
			fa->prior=q->prior;
			return true;
		}
	}
}

bool allocation()//分配资源
{
	int id,m_size;//输入的作业号和内存块大小
	cout<<"请输入作业编号(分区号)和申请的内存大小(KB):";
	cin>>id>>m_size;
	if(m_size<=0)//申请的内存大小小于等于0,申请失败
	{
		cout<<"申请的内存大小错误!请重新输入"<<endl;
		return false;
	}
	if(a=1)//首次适应算法
	{
		if(first_fit(id,m_size))
		{
			cout<<"内存分配成功!"<<endl;
			show();//显示内存分布
		}
		else
			cout<<"内存不足,分配失败!"<<endl;
		return true;
	}
	if(a=2)//最佳适应算法
	{
		if(best_fit(id,m_size))
		{
			cout<<"内存分配成功!"<<endl;
			show();//显示内存分布
		}
		else
			cout<<"内存不足,分配失败!"<<endl;
		return true;
	}
}

void recycle()//回收内存
{
	int id;
	cout<<"请输入想要释放的作业号:";
	cin>>id;
	DuNode *p=m_rid->next;//指向空闲队列的首地址
	DuNode *p1=NULL;//辅助向量
	while(p)//查找需要释放的作业的地址进行合并工作
	{
		if(p->data.ID==id)
		{
			p->data.ID=0;
			p->data.flag=0;
			if(!p->prior->data.flag)//与前一个空闲区相邻,则合并
			{
				p->prior->data.size+=p->data.size;
				p->prior->next=p->next;
				p->next->prior=p->next;
			}
			if(!p->next->data.flag)//与后一个空闲区相邻,则合并
			{
				p->data.size+=p->next->data.size;
				p->next->next->prior=p;
				p->next=p->next->next;
			}
			break;
		}
		p=p->next;
	}
	show();
}


void main()
{
	cout<<"*****************动态分区分配模拟*********************"<<endl;
	cout<<"************1.首次适应算法  2.最佳适应算法************"<<endl;
	cout<<"请输入要选择的分配算法:";
	cin>>a;
	init();//初始化内存块
	while(a!=1 && a!=2)
	{
		cout<<"输入错误!请重新输入:"<<endl;
		cin>>a;
	}
	while(1)
	{
		cout<<"**************************************************"<<endl;
		cout<<"*********1.申请内存 2.释放内存 3.退出*************"<<endl;
		cout<<"请输入操作数:";
		cin>>b;
		switch(b)
		{
		case 1:
			allocation();
			break;
		case 2:
			recycle();
			break;
		case 3:
		default:
				cout<<"动态分区分配算法结束!"<<endl;
				exit(1);
				break;
		}
	}
}

死锁避免银行家算法

目的和要求

目的
系统中有限的资源要供多个进程使用,保证得到的资源的进程能在有限的时间内归还资源,以供其他进程使用资源。
要求
每个进程的资源需求总量不能超过系统拥有的资源总数, 利用银行算法进行资源分配可以避免死锁。

内容与步骤

程序流程图
初始化算法流程图
在这里插入图片描述
银行家算法流程图
在这里插入图片描述
安全性算法流程图
在这里插入图片描述

运行结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

问题及心得

通过此次实验,解决了银行家死锁问题,通过初始化函数,调用银行家算法,进行安全算法的检查,最终正确合理地分配了资源,成功地避免了死锁问题,得出了相关的安全序列。此次的界面通过web显示出来,js脚本语言还需要进一步地加强,出现了一点逻辑问题,并且安全序列也没有很好地解决,存在一些冲突性事件。

C语言实现关键代码

安全性算法

//安全性算法
bool SafeAlgorithm()
{
	int i,j;
	//初始化Finish向量
	for(i=0;i<n;++i)
	{
		Finish[i]=false;
	}
	//初始化工作向量
	for(j=0;j<m;++j)
	{
		Work[j]=Available[j];
	}

	int iProcNum;
	//选择满足条件的进程
	i=0;
	while(SelectProcess(iProcNum))
	{
		Finish[iProcNum]=true;
		PrintSafeSeries(iProcNum);//输出此时利用安全性算法的分析情况
		int k;
		for(k=0;k<m;++k)
		{
			Work[k]+=Allocation[iProcNum][k];
		}
		SafeSeries[i++]=iProcNum;//进程号加入安全序列数组
	}

	if(IsSafe())
	{
		return true;//存在一个安全序列
	}
	return false;//不存在一个安全序列
}

银行家算法

//银行家算法
void BankAlgorithm()
{
	int i,j;
	cout<<"请输入请求分配的进程号(0-"<<n-1<<"):";
	cin>>i;
	cout<<"请依次输入进程P"<<i<<"对"<<m<<"类资源的请求分配量:";
	for(j=0;j<m;++j)
	{
		cin>>Request[i][j];
	}

	//步骤一
	for(j=0;j<m;++j)
	{
		if(Request[i][j]>Need[i][j])
		{
			cout<<"请求的资源已超过该资源宣布的最大值,请求资源失败!!"<<endl;
			return;
		}
	}

	//步骤二
	for(j=0;j<m;++j)
	{
		if(Request[i][j]>Available[j])
		{
			cout<<"没有足够的资源,请求资源失败!!"<<endl;
			return;
		}
	}

	//步骤三
	//系统试探着把资源分配给进程Pi,并修改相应的数值
	for(j=0;j<m;++j)
	{
		Available[j]-=Request[i][j];
		Allocation[i][j]+=Request[i][j];
		Need[i][j]-=Request[i][j];
	}

	//步骤四
	//系统执行安全性算法
	if(!SafeAlgorithm())//检测到不安全,则恢复到原来的状态
	{
		for(j=0;j<m;++j)
		{
			Available[j]+=Request[i][j];
			Allocation[i][j]-=Request[i][j];
			Need[i][j]+=Request[i][j];
		}
	}
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值