一、实验目的:
通过模拟实现请求页式存储管理的几种基本页面置换算法,了解虚拟存储技术的特点,掌握虚拟存储请求页式存储管理中几种页面置换算法的基本思想和实现过程,并比较它们的效率。
二、实验内容:
本实验要求使用C语言编程模拟一个拥有若干个虚页的进程在给定的若干个实页中运行、并在缺页中断发生时分别使用FIFO、OPT和LRU算法进行页面置换的情形。
三、程序分析与设计:
1、算法思想和算法流程设计
先进先出页面置换算法总是淘汰最先进入内存的页面。最佳置换算法所选择的被淘汰页面将是以后永不使用的或是在最长未来时间内不再被访问的页面。最近最久未使用置换算法选择最近最久未使用的页面允以淘汰,该算法赋予每个页面一个访问字段用来记录一个页面自上次被访问以来所经历的时间t,当需要淘汰一个页面时,选择现有页面中其t值最大的允以淘汰。
四、源程序
#include "stdio.h"
#include "stdlib.h"
typedef struct item
{
int num;//页号
int time;//等待时间,LRU算法会用到这个属性
}Pro;
int pageNum;//系统分配给作业的主存中的页面数
int memoryNum;//可用内存页面数
void FIFO(Pro *memory,Pro *page);//先进先出页面置换算法
void OPT(Pro *memory,Pro *page);//最佳页面置换算法
void LRU(Pro *memory,Pro *page);//最近最久未使用置换算法
void print(Pro *page1);//打印当前主存中的页面
int Search(int num1, Pro *memory1);//在页面集memory1中查找num1,如果找到,返回其在memory1中的下标,否则返回-1
int Max(Pro *memory1);//返回等待时间最长的页面的下标值
int LongVisit(int num,int tag,Pro *memory1,Pro *page1);// 返回距现在最长时间后要访问的页面下标
/**
先进先出页面置换算法
**/
void FIFO(Pro *memory,Pro *page){
int curmemory = 0, missNum=0;
float missRate;
missNum = 0;
printf("FIFO页面置换情况: \n");
for(int i=0;i<pageNum;i++)
{
if(Search(page[i].num,memory)<0)//若在主存中没有找到该页面
{
missNum ++;//缺页数++
memory[curmemory].num=page[i].num;//将作业页面集中内容调入内存页面集
print(memory);//打印当前的页面
curmemory = (curmemory+1)%memoryNum;
}else{
print(memory);
}
}//end for
missRate = (float)missNum/pageNum;//缺页率
printf("缺页次数:%d 缺页率: %.2f%% 命中率: %.2f%%\n", missNum, missRate*100,(1-missRate)*100);
}
/**
最佳置换算法
**/
void OPT(Pro *memory,Pro *page){
int curmemory = 0, missNum=0;
float missRate;
printf("OPT页面置换情况: \n");
for(int i=0;i<pageNum;i++)
{
if(Search(page[i].num,memory)<0)//若在主存中没有找到该页面
{
if(i<memoryNum)//此时内存中未满,不需要置换
curmemory = i;
else
curmemory = LongVisit(page[i].num,i,memory,page);//找到需要被置换的页面
missNum ++;
memory[curmemory].num=page[i].num;
print(memory);//打印当前的页面
curmemory = (curmemory+1)%memoryNum;
}else{
print(memory);
}
}//end for
missRate = (float)missNum/pageNum;
printf("缺页次数:%d 缺页率: %.2f%% 命中率: %.2f%%\n", missNum, missRate*100,(1-missRate)*100);
}
/**
最近最久未使用置换算法
**/
void LRU(Pro *memory,Pro *page){
int curmemory = 0, missNum=0;
float missRate;
printf("LRU页面置换情况: \n");
for(int i=0;i<pageNum;i++)
{
for(int j=0;j<memoryNum;j++)
{
if(memory[j].num>=0)
memory[j].time++;
}
if(Search(page[i].num,memory)<0)//若在主存中没有找到该页面
{
missNum ++;
//printf("%d \n",curmemory);
if(i<3)
curmemory = i;
else
curmemory = Max(memory);//最久未使用
memory[curmemory].num=page[i].num;
memory[curmemory].time = 0;//重置等待时间
print(memory);
curmemory = (curmemory+1)%memoryNum;
}
else//在主存中找到了该页面
{
curmemory = Search(page[i].num,memory);
memory[curmemory].time=0;//重置等待时间
curmemory = (curmemory+1)%memoryNum;
print(memory);
}
}//end for
missRate = (float)missNum/pageNum;
printf("缺页次数:%d 缺页率: %.2f%% 命中率: %.2f%%\n", missNum, missRate*100,(1-missRate)*100);
}
/**
打印当前的页面
**/
void print(Pro *memory1)
{
int j;
for(j=0;j<memoryNum;j++)
printf("%d ", memory1[j].num);
printf("\n");
}
/**
在页面集memory1中查找num1,如果找到,返回其在memory1中的下标,否则返回-1
**/
int Search(int num1,Pro *memory1 )
{
int j;
for(j=0;j<memoryNum;j++)
{
if(num1==memory1[j].num)return j;
}
return -1;
}
/**
返回等待时间最长的页面的下标值
**/
int Max(Pro *memory1)
{
int max = 0;
for(int k=1;k<memoryNum;k++)
{
if(memory1[k].time > memory1[max].time)
max = k;
}
return max;
}
/**
LongVisit 返回距现在最长时间后要访问的页面下标
参数: 页号int num,页面集下标int tag,内存页面集Pro *memory1,作业页面集Pro *page1
返回值:int max
**/
int LongVisit(int num,int tag,Pro *memory1,Pro *page1)
{
int k,j,min[100],min_k;
for(k=0;k<memoryNum;k++)
min[k] = 500;
for(k=0;k<memoryNum;k++)//k变量用于循环变量内存页面集
{
j = tag;
do{
j++;
if(j>20)
break;
}while(page1[j].num!=memory1[k].num);//找到第一个命中页面的作业页面集下标
if(j<min[k])//在未来会出现
{
min[k] = j;
}
}
int max = 0;
for(int t=1;t<memoryNum;t++)
{
if(min[t]>min[max])
max = t;//找最远的未来
}
return max;
}
int main(void)
{
char c; //得到用户的输入字符,来选择相应的置换算法
Pro *page; //作业页面集
Pro *memory; //内存页面集
int i;
printf("输入系统分配给作业的主存中的页面数:");
scanf("%d", &pageNum);
printf("输入内存页面数:");
scanf("%d", &memoryNum);
page= (Pro*)malloc(sizeof(Pro)*pageNum);
memory= (Pro*)malloc(sizeof(Pro)*memoryNum);
printf("请输入这%d个页面号,用空格分隔\n",pageNum);
for(i=0;i<pageNum;i++)//初始化页面集
{
//printf("第 %d 个页面号为:", i);
scanf("%d", &page[i].num);
page[i].time=0; //等待时间开始默认为0
}
do{
for(i=0;i<memoryNum;i++) //初始化内存中页面
{
memory[i].num=-1; //页面为空用-1表示
memory[i].time=-1; //页面初始化等待时间为-1
}
printf("*****f|F:FIFO页面置换*****\n");
printf("*****o|O:OPT页面置换*****\n");
printf("*****l|L:LRU页面置换*****\n");
printf("*****请选择操作类型(f|F,o|O,l|L),按其它键结束******\n");
fflush(stdin);//清空输入缓冲区
scanf("%c", &c);
if(c=='f'||c=='F') //FIFO页面置换
{
FIFO(memory,page);
}//end if
if(c=='o'||c=='O') //最佳页面置换
{
OPT(memory,page);
}//end if
if(c=='l'||c=='L') //LRU页面置换
{
LRU(memory,page);
}//end if
}while(c=='f'||c=='l'||c=='o'||c=='F'||c=='L'||c=='O');
return 0;
}