一、实验目的
1、掌握分页式存储管理地址转换和缺页中断。
2、理解虚拟存储器概念。
二、实验内容
1、模拟分页式存储管理中硬件的地址转换和产生缺页中断
分页式虚拟存储系统是把作业信息的副本存放在磁盘上,当作业被选中时,可把作业的开始几页先装入主存且启动执行。为此,在为作业建立页表时,应说明哪些页已在主存,哪些页尚未装入主存。
作业执行时,指令中的逻辑地址指出了参加运算的操作存放的页号和单元号,硬件的地址转换机构按页号查页表,若该页对应标志为“1”,则表示该页已在主存,这时根据关系式“绝对地址=块号×块长+单元号”计算出欲访问的主存单元地址。如果块长为2的幕次,则可把块号作为高地址部分,把单元号作为低地址部分,两者拼接而成绝对地址。若访问的页对应标志为“0”,则表示该页不在主存,这时硬件发“缺页中断”信号,由操作系统按该页在磁盘上的位置,把该页信息从磁盘读出装入主存后再重新执行这条指令。
2、用先进先出(FIFO)页面调度算法处理缺页中断 在分页式虚拟存储系统中,当硬件发出“缺页中断”后,引出操作系统来处理这个中断事件。如果主存中已经没有空闲块,则可用FIFO页面调度算法把该作业中最先进入主存的一页调出,存放到磁盘上,然后再把当前要访问的页装入该块。调出和装入后都要修改页表中对应页的标志。
FIFO页面调度算法总是淘汰该作业中最先进入主存的那一页,因此可以用一个数组来 表示该作业已在主存的页面。假定作业被选中时,把开始的m个页面装入主存,则数组的元素可定为m个。
三、实验要求
1、分析程序所定义使用的数据结构;
2、分析程序的结构,画出程序流程图;
数据结构:
struct PageTable//页表信息结构体
{
bool Mark;//页标志,1表示该页已在内存,0表示该页不在内存
long Block;//块号
long Seat;//在磁盘上的位置
bool Upmark;//更新标志
}PageList[PageSize];
地址转换程序流程图:
FIFO页面置换算法程序流程图:
代码如下:
#include <stdio.h>
#include <string.h>
#include<conio.h>//getch函数输出
#include<iostream>//清屏函数
#define PageSize 100
#define BlockSize 128
#define M 4
struct PageTable//页表信息结构体
{
bool Mark;//页标志,1表示该页已在内存,0表示该页不在内存
long Block;//块号
long Seat;//在磁盘上的位置
bool Upmark;//更新标志
}PageList[PageSize];
long Sign;//队列标记
long P[M];//假设内存中最多允许M个页面
void PageInit()
{
memset(PageList,0,sizeof(PageList));//内存空间初始化
/*分页式虚拟存储系统初始化*/
PageList[0].Mark = 1;
PageList[0].Block = 4;
PageList[0].Seat = 0x11;
PageList[1].Mark = 1;
PageList[1].Block = 9;
PageList[1].Seat = 0x12;
PageList[2].Mark = 1;
PageList[2].Block = 7;
PageList[2].Seat = 0x13;
PageList[3].Mark = 1;
PageList[3].Block = 3;
PageList[3].Seat = 0x21;
}
void PageWork()//模拟分页式存储管理中硬件的地址转换和产生缺页中断过程
{
bool stop = 0;
long page = 0;//页号
long Shifting = 0;//页偏移
char s[128];
do{
printf("请输入页号和页内偏移:\n");
if(scanf("%ld %ld", &page, &Shifting) != 2)
{
scanf("%s",s);
if(strcmp(s,"exit") == 0)
{//如果输入的为"exit"那么就退出,进入重选页面
stop = 1;
}
}
else
{
if(PageList[page].Mark)
{//如果该页Mark标志位为1,说明该页在主存中
printf("绝对地址=%ld\n",PageList[page].Block*BlockSize + Shifting);//计算出绝对地址,绝对地址=块号*块长(默认128)+单元号
}
else
{
printf("该页号:%ld缺页\n",page);//如果该页Mark标志位为0,表示该页不在主存中,则产生了一次缺页中断
}
}
}
while(!stop);
}
void FIFOInit()
{
/*以下部分为用先进先出(FIFO)页面调度算法处理缺页中断的初始化,其中也包含了对于当前的存储期内容的初始化*/
Sign = 0;
P[0] = 0;
P[1] = 1;
P[2] = 2;
P[3] = 3;//对内存中的4个页面初始化并使目前排在第一位的为0
memset(PageList,0,sizeof(PageList));//内存空间初始化
PageList[0].Mark = 1;
PageList[0].Block = 5;
PageList[0].Seat = 011;
PageList[1].Mark = 1;
PageList[1].Block = 8;
PageList[1].Seat = 012;
PageList[2].Mark = 1;
PageList[2].Block = 9;
PageList[2].Seat = 013;
PageList[3].Mark = 1;
PageList[3].Block = 1;
PageList[3].Seat = 021;
}
void FIFOWork()
{
long page = 0;
long Shifting = 0;
long i = 0;
char s[100];
bool stop = 0;
do
{
printf("请输入指令的页号、页偏移,以及是否为内存指令:\n");
if(scanf("%ld %ld", &page, &Shifting) != 2)
{
scanf("%s",s);
if(strcmp(s,"exit") == 0)
{//如果输入为"exit"那么就退出,进入重选页面
stop = 1;
}
}
else
{
scanf("%s",s);
if(PageList[page].Mark)
{//如果该页Mark标志位为1,说明该页在主存中
printf("绝对地址=%ld\n",PageList[page].Block*BlockSize+Shifting);//计算绝对地址,绝对地址=块号×块长(128)+单元号
if(s[0] == 'Y' || s[0] == 'y')
{//内存指令
PageList[page].Upmark = 1;//修改标志为1
}
}
else
{
if(PageList[P[Sign]].Upmark)
{//当前页面被更新过,需把更新后的内容写回外存
PageList[P[Sign]].Upmark = 0;
}
PageList[P[Sign]].Mark = 0;//将Mark标志位置0,表示当前页面已被置换出去
printf("被置换出的页面(提示:0代表第一个页面,依次类推):\n%ld\n",P[Sign]);//显示根据FIFO算法被置换出去的页面
printf("被调入的页面:%ld\n",page);//显示根据FTFO算法被调入的页面
PageList[page].Block = PageList[P[Sign]].Block;//块号相同
PageList[page].Mark = 1;//将当前页面的标记置为1,表示已在主存中
P[Sign] = page;//保存当前页面所在的位置
Sign = (Sign + 1) % M;
}
}
printf("数组P的值为:\n");
for(i = 0; i < M; i++)
{//循环输出当前数组的数值,即当前在内存中的页面
printf("P[%ld]=%ld\n",i,P[i]);
}
getch();
system("cls");
}
while(!stop);
}
void select()
{//选择哪种方法进行
long index;
char s[128];
do
{
printf("请选择菜单:\n");
printf("1.页式地址转换\n");
printf("2.FFO页面的置换\n");
printf("(提示:输入exit退出程序)\n");
if(scanf("%d",&index) != 1)
{
scanf("%s",&s);
if(strcmp(s,"exit") == 0)
{//如果输入为exit则退出整个程序
return;
}
}
else
{
if(index == 1)//如果index=1说明选择的是模拟分页式存储管理中硬件的地址转换和产生缺页中断
{
PageInit();//页式初始化
PageWork();//页式进行模拟
}
if(index == 2)//如果index=2说明选择的是FFO算法来实现页面的置换
{
FIFOInit();//FIFO初始化
FIFOWork();//FIFO进行模拟
}
}
}
while(1);
}
int main()
{
printf(" ****************\n");
printf(" ****************\n");
printf("----->分割线<-----\n");
select();//选择题号
return 0;
}