近期在学习操作系统课程的时候,老师布置了相关的实验作业,其中有一项是写出页面置换算法,于是我对原有代码进行了些许修改和优化,使其更具有模块性(例如FIFO页面置换使去掉除主函数其他部分也能运行得到正确答案),下面给出代码:
#include<bits/stdc++.h>
using namespace std;
#define N 12 //序列长度
#define B 3 //分配给当前进程的内存块数
#define P 5 //进程的页面数
int List[N]; //页面访问序列
int change[N]; //记录每次被替换出去的页
int buf[B]; //buf是分配给进程的内存块
int result[B][N]; //置换的详细过程
int old; //指向将要换出去的页
int absent; //缺页次数
void init()//(public)重置
{
absent = 0;
memset(change,0,sizeof(change));
memset(buf,-1,sizeof(buf));
memset(result,0,sizeof(result));
}
void print()//(public)打印
{
//输出置换详细过程
printf("the result is:\n");
for(int i = 0; i < B; i++)
{
for(int j = 0; j < N; j++) printf("%3d",result[i][j]);
printf("\n");
}
//输出每次被置换出去的页
printf("\nthe page is changed:\n");
for(int i = 0; i < N; i++)
{
if(change[i] == -1) printf(" ");
else printf("%3d",change[i]);
}
//显示缺页次数及缺页率
printf("\nabsent:%d\n",absent);
printf("the absent vote is:%f\n",(float)absent / N);
}
int isInBuf(int num) //(public)是否在页表中,是则返回页号,否则返回-1
{
for (int i = 0; i < B; i++)//遍历内存块buf[]
{
if(buf[i] == num) return i; //找到
else if(buf[i] == -1) //有空闲内存块
{
absent++;
buf[i] = num;
return i;
}
}
//遍历完内存块没找到
absent++;
return -1;
}
int oldOPT(int index)//功能:返回未来的下次使用距离现在最久的页面位置
{
//优化:这里可以用空间换时间,定义二维数组next[][],从后往前遍历,预处理每个页号最近的使用时的下标,时间复杂度O(n)
int f[B]; memset(f,-1,sizeof(f)); //局部f[]记录内存中页面下次使用的时间
for(int i = 0; i < B; i++) //遍历内存块
{
bool flag = false;
for(int j = index; j < N; j++) // 判断物理块中的页面是否与未来页面相等
if(buf[i] == List[j]) {f[i] = j; flag = true; break;}
if(!flag) f[i] = N;
}
//寻找下次使用距离现在最久的页面
int res = 0,max = INT_MIN;
for (int i = 0; i < B; i++)
{
if (max < f[i])
{
max = f[i];
res = i;
}
}
return res;
}
void OPT() //OPT置换算法
{
printf("\nOPT:\n");
for(int i = 0; i < N; i++) //遍历访问序列list[]
{
int flag = isInBuf(List[i]);
if(flag == -1) //需置换页面
{
old = oldOPT(i);//找到将要换出去的页
change[i] = buf[old]; //记录要被换出的页号
buf[old] = List[i]; //置换
}
else change[i] = -1;
for(int j = 0; j < B; j++) result[j][i] = buf[j]; //保存当前内存页面情况
}
print();//打印
}
int oldLRU(int f[]) //功能: 返回最近最久未使用页面的位置
{
//优化:用队列,每次取出队首元素、入队尾,复杂度O(1)
int res = 0, max = INT_MIN;
for(int i = 0; i < B; i++)
{
if(f[i] > max)
{
max = f[i];
res = i;
}
f[i]++;
}
return res;
}
void LRU() //LRU置换算法
{
printf("\nLRU:\n");
int f[B]; memset(f,-1,sizeof(f)); //局部f[]记录内存中页面多久未被访问
for(int i = 0; i < N; i++)
{
int flag = isInBuf(List[i]);
old = oldLRU(f);
if(flag == -1) //需置换页面
{
change[i]=buf[old];
buf[old] = List[i];
f[old] = 0;
}
else //不需置换页面
{
f[flag] = 0;
change[i] = -1;
}
for(int j = 0; j < B; j++) result[j][i]=buf[j];//保存当前内存页面情况
}
print();
}
void FIFO() //自写FIFO置换算法
{
printf("\nFIFO:\n");
deque<int>dq;
for(int i = 0; i < N; i++) dq.push_back(-1);
int index = 0;
for(int i = 0; i < N; i++)
{
int flag = isInBuf(List[i]); //是否在内存块中
if(flag == -1) //不在,需置换页面(未满和已满)
{
change[i] = buf[index]; //当前index既是即将被换走的页号,也是即将进来的页号
dq.pop_front();//旧的出队
dq.push_back(List[i]);//新的进队
buf[index] = List[i]; //这里是因为print()跟buf有关,需要保存
index = (index + 1) % B; //指针后移
}
else change[i] = -1; //在内存块中,则无需操作
for(int j = 0; j < B; j++) result[j][i] = buf[j]; //保存当前内存页面情况
}
print();
}
int main()
{
//初始化
srand((int)time(NULL)); //初始化随机数种子
printf("The Random List:\n");
for (int i = 0; i < N; i++) //产生随机页面访问序列
{
List[i] = rand() % P + 1;
printf("%3d", List[i]);
}
printf("\n----------------------------------------------------------------\n");
init(); OPT();//OPT置换算法
init(); LRU();//LRU置换算法
init(); FIFO();//FIFO置换算法
return 0;
}