操作系统内存管理模拟系统的实现完整版Word文档格式.docx
《操作系统内存管理模拟系统的实现完整版Word文档格式.docx》由会员分享,可在线阅读,更多相关《操作系统内存管理模拟系统的实现完整版Word文档格式.docx(36页珍藏版)》请在冰豆网上搜索。
进程信息
内存分配
分区创建
进程申请
内存回收
打印分区
低级调度
前后两分区都不是空闲分区
前未空闲后空闲
前空闲后未空闲
前后两分区都是空闲分区
图2.1总体结构流程图
图2.1为总体结构流程图
2.1主程序
主函数既是程序的入口,又是程序的出口,通常我们还可以指定一个exitcode再退出,以表明程序最后的结果是什么样的。
由于主函数肩负着入口和出口的重任,所以最好不要把太多的细节方面的逻辑直接放在主函数内,这样不利于维护和扩展。
主函数应该尽量简洁,具体的实现细节应该封装到被调用的子函数里面去。
此主函数中包括很多功能模块,其中各功能模块用菜单方式选择,为我们提供了九个功能选项。
如图2.1所示
显示一系列功能模块
输入数字,判断数字是否为1—9
根据数字的值调用各功能模块函数
开始
结束
N
Y
图2.1主程序流程图
2.2创建进程模块
进程的创建也就有两种方式:
一是由操作系统创建,二是由父进程创建。
在系统启动时,操作系统会创建一些进程,他们承担着管理和分配系统资源的任务,这些进程通常被称为系统进程。
系统允许一个进程创建新进程,新进程即为子进程,子进程还可以创建新的子进程,形成进程树结构。
此创建进程模块可以输入自己想创建的进程数进而实现进程创建。
如图2.2所示
输入创建进程的个数
初始化进程申请队列
初始化进程分配队列
图2.2创建进程流程图
cout<
<
"
输入进程数目:
;
cin>
>
ProcessNum;
tapplyIndex=newin[ProcessNum];
assignPointer=newint[ProcessNum];
//初始化进程分配队列
maxApplyNum=ProcessNum;
pro=randomCreatPro(ProcessNum);
创建成功
2.3进程信息模块
进程又称任务,是一个动态的使用系统资源、处于活动状态的应用程序。
进程的管理由进程控制块PCB、进程调度、中断管理、任务队列等组成,它是linux文件系统、存储管理、设备管理和驱动程序的基础。
进程控制块PCB中包含了进程的所有信息,主要包括进程PID、进程所占有的内存区域、文件描述符和进程环境等信息。
如图2.3所示
进程是否创建
输出该进程信息
Y
图2.3进程信息流程图
Ifpro==NULL
returnERROR
Forinti=0;
i<
pro++,i++
Ifpro->
status==0
cout<
创建"
elseifpro->
status==1//进程状态
执行"
}elseifpro->
status==-1
status==2
就绪"
status==-2
未就绪"
endl
}
pro-=ProcessNum
创建成功
end
2.4进程申请模块
进程是否被创建
输入申请进程的数目
申请数目是否大于已创建数目
进程申请成功
图2.4进程申请模块图
进程申请模块实现进程申请进入分区,但实现进程申请的进程必须先被创建。
实现根据输入进程申请的个数,判断进程是否可以进入内存,修改进程状态。
申请进程,可以先输入申请进程的数目,进而查看申请进程的信息。
如图2.4所示
ntapplyProcessNum=0;
//每次申请进程数目
ntmaxApplyNum=0;
//最大可申请数目
int*applyIndex=NULL;
//申请进程队列
inttotalApplyNum=0;
//申请总数
int*assignPointer=NULL;
//已分配内存的进程队
2.5分区创建模块
创建分区之前首先要确定准备创建的分区类型。
有三种分区类型,它们是“主分区”、“扩展分区”和“逻辑分区”。
主分区是指直接建立在硬盘上、一般用于安装及启动操作系统的分区。
由于分区表的限制,一个硬盘上最多只能建立四个主分区,或三个主分区和一个扩展分区;
扩展分区是指专门用于包含逻辑分区的一种特殊主分区。
可以在扩展分区内建立若干个逻辑分区;
逻辑分区是指建立于扩展分区内部的分区。
没有数量限制。
如图2.5所示
随机分配内存大小
创建分区
图2.5分区创建模块流程图
begin
Nodep
if(head==NULL){
Cout分区未创建,请先创建分区ndl
else
p=head->
next
cout.fill('
'
)
Whilep!
=NULL
cout.width(3)
cout分区的大小
p=p->
next;
}
return创建成功
2.6内存分配模块
常见内存分配算法如下:
首次适应算法,从空闲分区链首开始查找。
循环适应算法,从上次找到的空闲分区开始查找。
最佳适应算法,是最小的空闲分区分配给作业。
最差适应算法,最差适应算法中,该算法按大小递减的顺序形成空闲区链,内存分配,第一次分配,从头结点开始,其他重上次分配的节点开始,然后从分配资源的进程开始分配,若分配的进程进已分配进程队列,则申请进程的偏移指针回首址,修改分配数。
如图2.6所示
伪代码
Nodep=head->
返回最大空闲结点
计数count
if(p==NULL)则
cout空闲链表不存在
否则do{
if(p->
status==0)则
Cout++
if(count==1)则p=q
否则if(p->
subarea.subareaSize>
q->
subarea.subareaSize)
该分区空闲吗?
分区长>
=SIZE?
度>
将状态位置为正在使用
返回分区号
取下一表项
选择所要的适应算法
要求按SIZE大小分区
取分区说明表第一项
表结束吗?
无法分配
图2.6内存分配模块流程图
2.7低级调度模块
低级调度又称为进程调度、短程调度,它决定就绪队列中的哪个进程将获得处理机,然后由分派程序执行把处理机分配给该进程的操作。
在批处理,分时,实时三类系统中,进程调度必须被配置,因而是一种最基本的调度。
与中级调度——交换,高级调度——作业调度相对应。
低级调度的功能:
保存处理机的现场信息。
按某种算法选取进程。
把处理器分配给进程。
如图2.7所示
是否存在已分配好资源的进程
选择一个就绪进程进入CPU
CPU正在调度
进程获得处理机,开始执行
图2.7低级调度模块流程图
Displayprocess()
Createlinklist()
Creatprocess()
Assignmemory()
Display()
Callbackmemory()
Main()
3函数关系调用图
如图3.1所示,为函数关系调用图,主函数main()调用其他九个模块,Cowattemper()调用Displyprocess(),Creatprocess()调用Randomcreatpro()总体结构流程如下图所示。
Cowattemper()
Applyforprocess()
Menu()
Randomcrearpro()
4测试结果
所谓程序调试是指对程序的查错与排错。
在编写完一个源程序之后,不要立即进行编译,而应对程序进行全面的人工检查一遍,检查无误后可以开始进行程序调试。
由编译系统进行检查、发现错误,根据编译系统提示的错误类型和警告及出现的位置,我们可以定位到错误地点进行修改,然后再编译,如此反复进行,直至不再出现错误位置,最后才进行程序的连接于运行调试完以后,下一步就是对程序进行测试,运行程序,向程序中输入数据,根据输出结果是否正确(是否符合自己的想法)来判断程序是否正确,如果不正确或不符合自己的目的,就需要对程序进行修改。
然后再调试,再测试,直至结果无误或符合要求后,测试才算结束,此时,程序才算是满足题目要求的正确程序。
4.1主界面调试结果
主界面调试结果是运行程序后出现的主界面,它包括了内存管理中的一系列应用,它主要包括,创建进程,进程信息,进程申请,分区创建,内存分配,内存回收,打印分区,低级调度等应用,我们可以选择1-9的数字进行相应的操作,如果写入除1-9以外的数字,程序运行将自动退出,不再运行。
图4.1主界面调试结果图
4.2创建进程调试结果
创建进程运行结果,我们可以根据主界面显示结果,选择数字1,进而进行创建进程,创建进程时,需要你先输入想要创建进程的数目,然后再创建进程。
其中创建的进程里面包括进程的大小和其运行状态。
如果写入除1-9以外的数字,程序运行将自动退出,不再运行。
图4.2创建进程调试结果图
4.3进程信息调试结果
进程信息调试结果。
我们可以根据主界面显示结果,选择数字2,进而可以查看进程的信息,进程的信息里面包括所创建进程的大小和进程的状态。
如果我们选择1和3-9的数字则进行相应的操作,如果写入除1-9以外的数字,程序运行将自动退出,不再运行。
图4.3进程信息调试结果图
4.4进程申请调试结果
进程申请调试结果,我们可以根据主界面显示结果,选择数字3,然后根据主界面的提示输入所要申请进程的数目,如果输入的申请进程的数目大于所创建进程的数目,则退出提示重新输入申请进程的数目。
然后再根据申请数目输入所要申请的进程,申请成功之后退出到主界面。
如果我们选择1,2和4-9的数字则进行相应的操作,如果写入除1-9以外的数字,程序运行将自动退出,不再运行。
图4.4进程申请调试结果图
4.5分区创建调试结果
分区创建调试结果,我们可以根据主界面显示结果,选择数字4,然后进程随机分配内存的大小,进而创建分区。
如果我们选择1,2,3和5-9的数字则进行相应的操作,如果写入除1-9以外的数字,程序运行将自动退出,不再运行。
图4.5分区创建调试结果图
4.6内存分配调试结果
内存分配调试结果,我们可以根据主界面显示结果,选择数字5,然后根据程序中所输入的内存分配算法:
首次适应算法,循环适应算法,最佳适应算法和最坏适应算法中选择其中一种分配算法,然后进行内存的分配。
如果我们选择1-4和6-9的数字则进行相应的操作,如果写入除1-9以外的数字,程序运行将自动退出,不再运行。
图4.6内存分配调试结果图
4.7内存回收调试结果
内存回收调试结果,我们可以根据主界面显示结果,选择数字6,然后调试结果就会显示正在执行的进程数,以及正在执行进程的大小和分配的分区号。
然后程序会提示你是否结束进程,如果选择是,程序调试将会继续显示主界面,如果选择否,程序调试会直接退出。
如果我们选择1-5和7-9的数字则进行相应的操作,如果写入除1-9以外的数字,程序运行将自动退出,不再运行。
图4.7内存回收调试结果图
4.8打印分区调试结果
打印分区调试结果,我们可以根据主界面显示结果,选择数字7,然后程序调试就会显示分区的大小,分区的开始地址以及此分区是否空闲等信息。
程序自动会进行分区的打印。
如果我们选择1-6和8-9的数字则进行相应的操作,如果写入除1-9以外的数字,程序运行将自动退出,不再运行。
图4.8打印分区调试结果图
4.9低级调度调试结果
低级调度调试结果,我们可以根据主界面显示结果,选择数字8,然后运行界面就会显示所创建进程的信息,然后我们可以选择所创建进程中的一个就绪进程进入cpu,然后cpu进行调度,最后获得处理机进行低级调度的执行。
如果我们选择1-7和9的数字则进行相应的操作,如果写入除1-9以外的数字,程序运行将自动退出,不再运行。
图4.9低级调度调试结果图
5源程序
#include<
iostream>
cmath>
iomanip.h>
time.h>
#defineSize4
#definenum10
#defineSUCCESS1
#defineERROR-1
typedefintbyte;
typedefstruct{
bytesubareaSize;
//分区大小
intstartLoc;
//起始地址
intindex;
//分区号
}SubareaTable;
//分区表
typedefstructnode{//结点
SubareaTablesubarea;
//分区
structnode*next;
intstatus;
//状态位0(空闲)1(使用)
}*Node,*LinkList;
byteprocessSize;
intsubareaIndex;
//保存分区号
//进程状态,0(新建)1(执行)-1(终止)-2(未绪。
申请但没有分配内存)2(就绪,已分配内存)
}Process;
//进程
intsubareaSize[num]={8,12,16,32,24,16,64,128,40,64};
Process*pro=NULL;
//保持进程信息
intProcessNum=0;
//进程数目
intapplyProcessNum=0;
intmaxApplyNum=0;
//已分配内存的进程队列
intassignFlag=0;
//分配索引,表示已申请队列已分配的进程数
intexeIndex;
//执行的进程号
Node*subareaNode=newNode[3];
//分区回收时,进程所在分区及其前,后分区信息
LinkListcreateLinkList(intn);
//建立空闲分区链
NodefirstFit(LinkList&
head,Processpro);
//首次适应算法
NodenestFit(LinkList&
head,Processpro,Nodeflag);
//循环适应算法
NodebestFit(LinkList&
//最佳适应算法
NodeworstFit(LinkList&
//最坏适应算法
Nodeassign(LinkList&
head,intorderIndex,intindex,NodeflagNode);
//一次分区分配
intassignMemory(LinkList&
head);
//内存分配
voidinsertNode(LinkList&
head,Nodeq,intindex);
//插入节点
NodedeleteNode(LinkList&
head,intindex);
//删除节点
intdisplay(LinkList&
//打印分区分配情况
intlowAttemper(int*excursionPointer);
//低级调度
intfindSubarea(LinkList&
//回收内存
intmenu();
//菜单
intcreatProcess();
//创建进程
Process*randomCreatPro(intn);
//随机产生进程
LinkListcreateLinkList(intn){//建立空闲分区链
-------------创建分区--------------"
endl;
LinkListhead;
Nodep;
head=(LinkList)malloc(sizeof(node));
头结点分配错误"
returnNULL;
}
head->
next=NULL;
//链表尾巴设置为NULL
LinkListq=head;
intstart=0;
for(inti=1;
=n;
i++){
p=(Node)malloc(sizeof(node));
if(p==NULL){
节点分配错误"
p->
next=q->
q->
next=p;
q=p;
subarea.index=i;
subarea.subareaSize=subareaSize[i-1];
//分区表赋值大小
subarea.startLoc=start;
status=0;
start+=subareaSize[i-1];
分区创建成功!
!
returnhead;
head,Processpro){//首次适应算法
Nodep=head->
//遍历结点,返回结点,从第一个结点开始遍历
空闲链表不存在"
else{
do{
if(p->
status==0&
&
p->
=pro.processSize){
break;
while(p!
=NULL);
if(p==NULL){//没找到合适的结点
returnp;
head,Processpro,Nodeflag){//循环适应算法
Nodep=flag->
//遍历结点
while(p!
=NULL){
if(p==NULL){//遍历到链表结尾
p=head;
//从头开始遍历
=flag){//标记结点
if(p==flag){//正常跳出循环,没有合适的结点可分配
}else{
//在flag结点前找到一合适的结点分配
}else{
//在flag结点后找到一合适的结点分配
head,Processpro){//最佳适应算法
Nodeq;
//返回最佳空闲结点
intleave;
//剩余空间
intcount=0;
//计数器
do{
=pro.processSize){
count++;
if(count==1){//第一个可以分配的空闲分区
leave=p->
subarea.subareaSize-pro.processSize;
}elseif(count>
1){
subarea.subareaSize-pro.pro