实验请求式分页存储管理算法设计与实现
1.实验内容:模拟请求页式存储管理中硬件的地址转换和缺页中断,并用先进先出调度算法(FIFO)处理缺页中断;
2.要求:
① 指令序列的设定可以执行拟定,格式如表3;
② 在完成了FIFO换页策略后,可以选做LRU的换页策略,并进行比较;
③ 作业允许的页架数m在不同情况下的缺页中断率;
④ 程序运行时显示地址转变和页面调入调出过程。
3.步骤:
① 设计页表及其数据结构:
页号
标志:是否在主存;
页架号:设定页表在主存的位置;
修改标志:设定页面在主存中是否修改过;
磁盘上位置:设定页面在辅存中的位置;
例如:装入新页置换旧页时,若旧页在执行中没有被修改过,则不必将该页重写磁盘。因此,页表中增加是否修改过的标志,执行“存”指令和“写”指令时将对应的修改标志置成“1”表示修改过,否则为“0”表示未修改过。
表 1 页表格式
|页号 标志 页架号 修改标志 在磁盘上位
②设计一个地址转换程序半模拟硬件的地址转换和缺页中断。
当访问的页在主存时则形成绝对地址,但不去模拟指令的执行,可以输出转换后的绝对地址来表示一条指令已执行完成。当访问的页不在主存中时,则输出“*页号”来表示硬件产生了一次缺页中断。模拟地址转换流程见图1.1。
③ 设计FIFO页面调度程序;
FIFO页面调度算法总是先调出作业中最先进入主存中的哪一页。因此可以用一个数组来表示(或构成)页号队列。数据中每个元素是该作业已在主存中的页面号,假定分配给作业的页(架)数为m,且该作业开始的m页已装入主存,则数组可由m个元素构成。
P[0],P[1],P[2],…,P[m-1]
它们的初值为P[0]:=0,P[1]:=1,P[2]:=2,…,P[m-1]:=m-1
用一指针K指示当要调入新页时应调出的页在数组中的位置,K的初值为“0”,当产生缺页中断后,操作系统总是选择P[K]所指出的页面调出,然后执行。
④ 设计输入数据和输出格式;
如: 假定主存中页架大小为1024个字节,现有一个共7页的作业,其副本已在磁盘上。系统为该作业分配了4个页架,且该作业的第0页至第3页已装入内存,其作3页未主存,该作业的页表如下:
页号 标志 页架号 修改标志 在磁盘上位置
0 1 5 0 011
1 1 8 0 012
2 1 9 0 013
3 1 1 0 021
4 0 0 022
5 0 0 023
6 0 0 121
如果该作业依次执行的指令序列如附表3所示:
操作 页号 页内地址 操作 页号 页内地址
- 0 070 移位 4 053
- 1 050 + 5 023
× 2 015 存 1 037
存 3 021 取 2 078
取 0 056 + 4 001
- 6 040 存 6 084
依次执行上述指令调试你所设计的程序(仅模拟指令的执行,不考虑序列中具体操作的执行)。
⑤ 编程上机,验证结果。
4.实验报告:
为进一步考察程序的执行,可自行确定若干组指令,运行程序,核对执行结果实验报告:
① 实验题目;
② 程序中所用的数据结构及说明;
③ 打印一份源程序并附上必要的说明;
④ 按照指令的执行序列,打印输出结果:绝对地址或调出、调入的页号。
P[K]:=要装入的新页页号
K:=(k+1)mod m
在实验中不必实际地启动磁盘执行调出一页和装入一页的工作,而用输出“OUT调出的页号”和“IN要装入的新页页号”来模拟一次调出和装入过程,模拟程序的流程图见附图1.1。
按流程控制过程如下:
提示:输入指令的页号和页内偏移和是否存指令 ,若d为-1则结束,否则进入流程控制过程,得P1和d,查表在主存时绝对地址P1×1024+d
大概实验指导书就是这样,自己根据网上的代码和自己的实验指导书进行了编写,实验当中出现的问题还是比较多的,这个代码大家使用的时候注意一下可以直接在结构体后面,直接给数组赋值,我开始写的时候比较凌乱一些。不过结果是对的
# include<stdio.h>
# include<string.h>
# include<stdlib.h>
#include<math.h>
# include<iostream.h>
# define N 1000
struct zhiling
{
char caozuo[5];//操作
int yehao1;//页号
int yeneidizhi;//页内标志
}zhiling[N]={{"+",0,70},{"-",1,50},{"*",2,15},{"cun",3,21},{"qu",0,56},{"-",6,40},{"yi",4,53},{"+",5,23},{"cun",1,37},{"qu",2,78},{"+",4,1},{"cun",6,84}};
struct yebiao
{
int yehao;//页号
int biaozhi;//标志
int yejiahao;//页架号
int xiugaibiaozhi;//修改标志
int cipanweizhi;//磁盘位置
}yebiao[N];
int p[4]={0,1,2,3};//装入主存的页号(用数组装入)
void init()//页表的初值化
{
int i;
for(i=0;i<4;i++)
{
yebiao[i].yehao=i;
yebiao[i].biaozhi=1;
yebiao[i].xiugaibiaozhi=0;
}//标志前四个页号在主存当中将标志置为1,修改标志为0;
for(i=4;i<8;i++)
{
yebiao[i].yehao=i;
yebiao[i].biaozhi=0;
yebiao[i].xiugaibiaozhi=0;
}//标志后三个的页号不在主存当中将标志置为0,修改标志为0;
yebiao[0].yejiahao=5;
yebiao[1].yejiahao=8;
yebiao[2].yejiahao=9;
yebiao[3].yejiahao=1;//对0—3的页号设定页架号,即(设定页表在主存的位置)
yebiao[4].yejiahao=-1;
yebiao[5].yejiahao=-1;
yebiao[6].yejiahao=-1;//将没有设定页架号的页架号都设定为-1,便于后面的交换
yebiao[0].cipanweizhi=11;
yebiao[1].cipanweizhi=12;
yebiao[2].cipanweizhi=13;
yebiao[3].cipanweizhi=21;
yebiao[4].cipanweizhi=22;
yebiao[5].cipanweizhi=23;
yebiao[6].cipanweizhi=21;//对于0—6的页号的磁盘位置赋值(设定页表在辅存当中的位置)
}
/*void init2()//指令序列的初值化
{
int j;
for(j=0;j<12;j++)
zhiling[0].caozuo[5]='+';
zhiling[1].caozuo[5]='-';
zhiling[2].caozuo[5]='*';
strcpy((char *)&zhiling[3].caozuo[5],"c");
strcpy((char *)&zhiling[4].caozuo[5],"q");
zhiling[5].caozuo[5]='-';
strcpy((char *)&zhiling[6].caozuo[5],"y");
zhiling[7].caozuo[5]='+';
strcpy((char*)&zhiling[8].caozuo[5],"c");
strcpy((char*)&zhiling[9].caozuo[5],"q");
zhiling[10].caozuo[5]='+';
strcpy((char*)&zhiling[11].caozuo[5],"c");//对于操作进行初始化
zhiling[0].yehao1=0;
zhiling[1].yehao1=1;
zhiling[2].yehao1=2;
zhiling[3].yehao1=3;
zhiling[4].yehao1=0;
zhiling[5].yehao1=6;
zhiling[6].yehao1=4;
zhiling[7].yehao1=5;
zhiling[8].yehao1=1;
zhiling[9].yehao1=2;
zhiling[10].yehao1=4;
zhiling[11].yehao1=6;//对于页表号进行初始化
zhiling[0].yeneidizhi=70;
zhiling[1].yeneidizhi=50;
zhiling[2].yeneidizhi=15;
zhiling[3].yeneidizhi=21;
zhiling[4].yeneidizhi=56;
zhiling[5].yeneidizhi=40;
zhiling[6].yeneidizhi=53;
zhiling[7].yeneidizhi=23;
zhiling[8].yeneidizhi=37;
zhiling[9].yeneidizhi=78;
zhiling[10].yeneidizhi=01;
zhiling[11].yeneidizhi=84;//对于页内地址进行初始化
}*/
void print1()//输出页表
{
cout<<"*********************作业的页表*********************"<<endl;
int i;
for(i=0;i<7;i++)
{
cout<<" 页号 "<<yebiao[i].yehao;
cout<<" 页内标志 "<<yebiao[i].biaozhi;
cout<<" 页架号 "<<yebiao[i].yejiahao;
cout<<" 修改标志 "<<yebiao[i].xiugaibiaozhi;
cout<<" 磁盘位置 "<<yebiao[i].cipanweizhi;
cout<<endl;
}
}
void print2()//输出执行的指令
{
cout<<"*********************作业的执行指令*********************"<<endl;
int i;
for(i=0;i<12;i++)
{
cout<<" 操作 "<<zhiling[i].caozuo[5];
cout<<" 页号 "<<zhiling[i].yehao1;
cout<<" 页内标志 "<<zhiling[i].yeneidizhi;
cout<<endl;
}
}
void zhuanhuan()//输出作业执行调度算法,先入先出算法
{
cout<<"*********************作业的执行*********************"<<endl;
int i;
int biaozhi1,
jiaohuanyehao,
yehao3,xiugaibiaozhi1;//定义一个临时的变量,标志,交换页号,页号
int k=0;//定义数组的头
int m=4;//定义数组的长度
long jueduidizhi;
for(i=0;i<12;i++)//作业执行指令序列,12个
{
yehao3=zhiling[i].yehao1;//yehao3等于指令操作对的页号
biaozhi1=yebiao[yehao3].biaozhi;//biaozhi1是yehao3对应的标志标志是否在内存
cout<<"操作为 "<<zhiling[i].caozuo<<"页号为 "<<zhiling[i].yehao1<<"页内标志为 "<<zhiling[i].yeneidizhi<<endl;//执行的指令序列为
cout<<"页号 "<<yehao3<<"中执行"<<endl;//yehao3执行
if(biaozhi1==1)//如果标志等于1则证明在内存当中形成绝对地址
{
jueduidizhi=yebiao[yehao3].yejiahao*1024+zhiling[i].yeneidizhi;//绝对地址=内存页架号*页架的大小+页内地址
if(zhiling[i].caozuo=="cun")//判断是否是存指令
{
yebiao[yehao3].xiugaibiaozhi=1;//是则修改标志置为1
cout<<"绝对地址是 "<<jueduidizhi<<endl;//输出绝对地址
}
else
{
cout<<"绝对地址是 "<<jueduidizhi<<endl;//不是则直接输出绝对地址
}
}
if(biaozhi1==0)//如果标志位不是1的时候直接输出*页号
{
cout<<"页号 *"<<yehao3<<endl;//如果页号不在主存块当中输出*页号表示发生了中断
jiaohuanyehao=p[k];//队列的头指针;
cout<<"把页号为 "<<jiaohuanyehao<<" 置换"<<endl;
xiugaibiaozhi1=yebiao[jiaohuanyehao].xiugaibiaozhi;
if(xiugaibiaozhi1==1)//执行指令的页号的修改位判断
{
cout<<"调出的页号为 "<<jiaohuanyehao<<endl;//修改位是1输出要置换的页号
cout<<"要装入的新页页号 "<<yehao3<<endl;
}
else
{
cout<<"要装入的新页页号 "<<yehao3<<endl;//修改位是0,输出要进入的新的页表
}
yebiao[yehao3].biaozhi=yebiao[jiaohuanyehao].biaozhi; //交换标志是否在主存当中
yebiao[yehao3].yejiahao=yebiao[jiaohuanyehao].yejiahao;
yebiao[jiaohuanyehao].yejiahao=-1;
yebiao[jiaohuanyehao].biaozhi=0;
p[k]=yehao3;
k=(k+1)%m;//数组队列向前走
yebiao[jiaohuanyehao].xiugaibiaozhi=0;
yebiao[yehao3].xiugaibiaozhi=1;
}
}
}
void main()
{
init();
//init2();
print1();
print2();
zhuanhuan();
}