【实验目的】
1.加深对页面置换算法的理解。
2.掌握几种页面置换算法的实现方法。
3.通过实验比较各种置换算法的优劣。
【实验内容】
参考用C语言实现的先进先出算法FIFO的代码,实现最佳置换算法OPT和最近最少使用算法LRU。使得随机给出一个页面执行序列,计算不同置换算法的缺页数,缺页率和命中率。
假定系统为某进程分配了三个物理块,并考虑有以下的页面号引用串:
7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1
【实验步骤】
1.数据结构
typedef struct item
{
int num;//页号
int time;//等待时间,LRU算法会用到这个属性
int isFind;//用于LRU算法中查找判定条件,以保证memory中的各个值只被检索一次
}Pro;
typedef struct memoryBlockIndexInPage
{
int index;
int isOccur;
}temp;//temp用于记录memory数组中的各个页号在page中出现的位置及是否在未来出现过
int pageNum;//系统分配给作业的主存中的页面数//分配的大小
int memoryNum;//可用内存页面数//可用
void print(Pro* page1);//打印当前主存中的页面
int Search(int num1,Pro* memory1);//在页面集memory1中查找num1,如果找到,返回其在memory1中的下标,否则返回-1
int compareNum_Big(int num1, int num2);//返回两个数中的较大者,该函数用于OPT置换算法
int compareNum_Small(int num1, int num2);//返回两个数中的较大者,该函数用于LRU置换算法
void print(Pro* memory1)//打印当前的页面
//在页面集memory1中查找num1,如果找到,返回其在memory1中的下标,否则返回-1
int Search(int num1, Pro* memory)
2.程序流程图
3.实验代码
#include <stdio.h>
#include <stdlib.h>
typedef struct item
{
int num;//页号
int time;//等待时间,LRU算法会用到这个属性
int isFind;//用于LRU算法中查找判定条件,以保证memory中的各个值只被检索一次
}Pro;
typedef struct memoryBlockIndexInPage
{
int index;
int isOccur;
}temp;//temp用于记录memory数组中的各个页号在page中出现的位置及是否在未来出现过
int pageNum;//系统分配给作业的主存中的页面数//分配的大小
int memoryNum;//可用内存页面数//可用
void print(Pro* page1);//打印当前主存中的页面
int Search(int num1,Pro* memory1);//在页面集memory1中查找num1,如果找到,返回其在memory1中的下标,否则返回-1
int compareNum_Big(int num1, int num2);//返回两个数中的较大者,该函数用于OPT置换算法
int compareNum_Small(int num1, int num2);//返回两个数中的较大者,该函数用于LRU置换算法
int main()
{
int i;
int curmemory;//调入主存中的页面个数//内存中已调入的进程数量
int missNum;//缺页次数
float missRate;//缺页率
char c;//得到用户的输入字符,来选择相应的置换算法
Pro* page;//作业页面集//进程
Pro* memory;//内存页面集//能容纳的最多的进程的数量
printf("输入系统分配给作业的主存中的页面数:");
scanf("%d", &pageNum);
printf("输入内存页面数:");
scanf("%d", &memoryNum);
page = (Pro*)malloc(sizeof(Pro) * pageNum);
memory = (Pro*)malloc(sizeof(Pro) * memoryNum);
for(i = 0;i < pageNum;i++)
{
printf("第%d个页面号为:\n", 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;//
}
printf("*****f:FIFO页面置换*****\n");
printf("*****o:OPT页面置换*****\n");
printf("*****l:LRU页面置换*****\n");
printf("*****请选择操作类型(f,o,l),按其它键结束******\n");
fflush(stdin);
scanf("%c", &c);
i = 0;
curmemory = 0;
if(c == 'f')//FIFO页面置换
{
missNum = 0;
printf("FIFO页面置换情况:\n");
printf("置换的页面号 ");
for(i = 0;i < memoryNum;i++)
printf("物理块号%d ", i+1);
printf("\n");
printf("———————————————————————————————————\n");
for(i = 0;i < pageNum;i++)
{
if(Search(page[i].num, memory) < 0)//若在主存中没有找到该页面
{
missNum++;
if(i < 3)
printf(" — ");
else
printf(" %2d ", memory[curmemory].num);//输出被置换的页号
memory[curmemory].num = page[i].num;//内存[内存中已调入进程的数量].页号 = 录入进程的页号
print(memory);
printf("———————————————————————————————————\n");
curmemory = (curmemory+1) % memoryNum;
}
}//endfor
missRate = (float)missNum / pageNum;
printf("缺页次数:%d\t缺页率:%f\n", missNum, missRate);
}//endif
if(c == 'o')//OPT页面置换
{
missNum = 0;
printf("Optimal页面置换情况: \n");
printf("置换的页面号 ");
for(i = 0;i < memoryNum;i++)
printf("物理块号%d ", i+1);
printf("\n");
printf("———————————————————————————————————\n");
for(i = 0;i < pageNum;i++)
{
if(Search(page[i].num, memory) < 0)//若在主存中没有找到该页面
{
missNum++;
if(i < 3)
{
printf(" — ");
memory[curmemory].num = page[i].num;//内存[内存中已调入进程的数量].页号 = 录入进程的页号
print(memory);
printf("———————————————————————————————————\n");
curmemory = (curmemory+1) % memoryNum;
}
else
{
temp tempRecord[3] = {{0,0},{0,0},{0,0}};
//查找要置换的页号
int j, k, comparatorCount = 0;//comparatorCounter记录要比较的值的数量
for(j = 0;j < memoryNum;j++)
{
for(k = i + 1;k < pageNum;k++)
{
if(page[k].num == memory[j].num)//如果未来的页面在内存块中
{
tempRecord[j].index = k;//记下该未来页面的下标
tempRecord[j].isOccur = 1;//tempRecord[j]在未来出现了
comparatorCount++;
break;
}
}
}
//从tempRecord数组中找出要置换的目标索引
int target_InsteadIndex = 0;
switch(comparatorCount)
{
case 0:
break;
case 1:
case 2:
for(j = 0;j < 3;j++)
{
if(tempRecord[j].isOccur == 0)//如果这个页号在未来没有出现
{
curmemory = j;
break;
}
}
break;
case 3:
target_InsteadIndex = compareNum_Big(compareNum_Big(tempRecord[0].index, tempRecord[1].index), tempRecord[2].index);
break;
}
//找出memory中要换出的下标
for(j = 0;j < memoryNum;j++)
{
if(memory[j].num == page[target_InsteadIndex].num)
{
curmemory = j;
break;
}
}
printf(" %2d ", memory[curmemory].num);//输出被置换的页号
memory[curmemory].num = page[i].num;//内存[内存中已调入进程的数量].页号 = 录入进程的页号
print(memory);
printf("———————————————————————————————————\n");
}
}
}//endfor
missRate = (float)missNum / pageNum;
printf("缺页次数:%d\t缺页率:%f\n", missNum, missRate);
}//endif
if(c == 'l')//LRU页面置换
{
int j, k;
missNum = 0;
printf("LRU页面置换情况:\n");
printf("置换的页面号 ");
for(i = 0;i < memoryNum;i++)
printf("物理块号%d ", i+1);
printf("\n");
printf("———————————————————————————————————\n");
for(i = 0;i < pageNum;i++)
{
if(Search(page[i].num, memory) < 0)//若在主存中没有找到该页面
{
missNum++;
if(i < 3)
{
printf(" — ");
memory[curmemory].num = page[i].num;//内存[内存中已调入进程的数量].页号 = 录入进程的页号
curmemory = (curmemory+1) % memoryNum;
}
else
{
for(j = i-1;j >= 0;j--)//遍历当前要插入的页号位置之前的页号
{
for(k = 0;k < memoryNum;k++)//遍历内存块中的页
{
if(page[j].num == memory[k].num && memory[k].isFind != 1)//如果之前的页号被访问过
{
memory[k].time = j;
memory[k].isFind = 1;
break;
}
}
}
int minTime = compareNum_Small(compareNum_Small(memory[0].time, memory[1].time), memory[2].time);
for(j = 0;j < memoryNum;j++)
{
if(memory[j].time == minTime)
{
curmemory = j;
break;
}
}
printf(" %2d ", memory[curmemory].num);//输出被置换的页号
memory[curmemory].num = page[i].num;//内存[内存中已调入进程的数量].页号 = 录入进程的页号
}
print(memory);
printf("———————————————————————————————————\n");
for(j = 0;j < memoryNum;j++)
{
memory[j].isFind = 0;
}
}
}//endfor
missRate = (float)missNum / pageNum;
printf("缺页次数:%d\t缺页率:%f\n", missNum, missRate);
}//endif
}while(c == 'f' || c == 'l' || c == 'o');
return 0;
}
void print(Pro* memory1)//打印当前的页面
{
int j;
for(j = 0;j < memoryNum;j++)
printf("%2d ", memory1[j].num);
printf("\n");
}
//在页面集memory1中查找num1,如果找到,返回其在memory1中的下标,否则返回-1
int Search(int num1, Pro* memory)
{
int j;
for(j = 0;j < memoryNum;j++)
{
if(num1 == memory[j].num)
return j;
}
return -1;
}
int compareNum_Big(int num1, int num2)
{
return num1 >= num2 ? num1 : num2;
}
int compareNum_Small(int num1, int num2)
{
return num1 <= num2 ? num1 : num2;
}