操作系统——模拟页面置换算法(FIFO——先入先出、LRU——最近最少使用、LFU——最近最不常使用),计算置换率(包含程序框图)
导语:
1. FIFO页面置换算法:最简单的页面置换算法。这种算法的基本思想是:当需要淘汰一个页面时,总是选择驻留主存时间最长的页面进行淘汰,即先进入主存的页面先淘汰。(看时间)
2. LRU页面置换算法:最近最少使用,简单来说就是将数据块中,每次使用过的数据放在数据块的最前端,然后将存在的时间最长的,也就是数据块的末端的数据置换掉。(看时间)
3. LFU页面置换算法:近期最少使用算法,选择近期最少访问的页面作为被替换的页面,如果一个数据在最近一段时间内使用次数很少,那么在将来一段时间内被使用的可能性也很小。(看次数)
4. 置换率与与缺页率不同。置换率用置换次数算,缺页率用缺页中断次数算。
FIFO页面置换算法:
Linux效果图(采用UOS + VScode + g++)

程序框图

C++代码(FIFO):
#include<iostream>
using namespace std;
static int mnum;
//物理块数
static int pnum;
//页面走向
static int count=0;
//页面置换次数
static int *analogblock;
//模拟物理块
static int *block;
//物理块
static int *process;
//随机页面访问序列
int judge(int a[],int n,int x) //判断数组中是否已有x,若有返回其下标值,没有则返回-1 {
int i;
for (i=0;i<n;i++)
if(x==a[i])
return i;
return -1;
}
void replace(int y,int mnum,int x)//用于物理块页面置换,y是用来置换的页面,x是被置换的页面 {
int i;
for (i=0;i<mnum;i++)
if(x==block[i])
block[i]=y;
}
int main() {
int i;
int maxanalogblock=-1;
//模仿队列的定义
int x;
cout<<"请输入页框大小物理块数:\n";
cin>>mnum;
if(mnum>999999) {
cout<<"输入超出控制大小!"<<endl;
return 0;
}
cout<<"自动生成的内存块需求序列个数:\n";
cin>>pnum;
if(pnum>999999) {
cout<<"输入超出控制大小!"<<endl;
return 0;
}
analogblock=new int[mnum];
block=new int[mnum];
process=new int[pnum];
for (i=0;i<mnum;i++) analogblock[i]=-1;
for (i=0;i<mnum;i++) block[i]=-1;
/////////////////////
//随机产生页面走向序列
cout<<"产生随机序列如下:\n";
srand( (unsigned)time( NULL ) );
//以time函数值(即当前时间)作为种子数,保证两次产生序列的随机性
for (i=0; i<pnum; i++) {
process[i] = rand()%10;
cout<<process[i]<<" ";
}
cout<<endl;
//////////////////////
cout<<"先进先出(FIFO)页面置换算法,结果: \n\n";
//////////////////////
for (x=0;x<pnum;x++) //自动读数 {
//读一个序列号,输出当前数组元素
cout<<"真实物理块情况:";
for (i=0;i<mnum;i++) {
if(block[i]!=-1)
cout<<block[i]<<" ";
}
cout<<"模拟物理块情况:";
for (i=0;i<mnum;i++) {
if(analogblock[i]!=-1)
cout<<analogblock[i]<<" ";
}
//////////////////////////
maxanalogblock++;
//读数后maxanalogblock自动+1
if(maxanalogblock<mnum) //若在物理块范围内 {
if(judge(analogblock,mnum,process[x])==-1)//若数组中不存在待插入元素 {
analogblock[maxanalogblock]=process[x];
//新元素从尾部插入
block[maxanalogblock]=process[x];
//新元素从尾部插入
cout<<" 第"<<x+1<<"次访问,页面"<<process[x]<<" 缺页中断 调入页面"<<process[x]<<endl;
} else //若数组中存在待插入元素 {
maxanalogblock--;
//因为没有插入新元素,回滚maxanalogblock值
cout<<" 第"<<x+1<<"次访问,页面"<<process[x]<<" 已存在 直接访问"<<endl;
}
} else //超过物理块数的元素 {
if(judge(analogblock,mnum,process[x])==-1)//若数组中不存在待插入元素 {
//队列法插入(尾部元素出,新元素从头部入)
cout<<" 第"<<x+1<<"次访问,页面"<<process[x]<<" 缺页中断 页面"<<process[x]<<"置换出页面"<<analogblock[0]<<endl;
replace(process[x],mnum,analogblock[0]);
//置换物理块中页面
for (i=0;i<mnum-1;i++)
analogblock[i]=analogblock[i+1];
analogblock[mnum-1]=process[x];
//////////////////
maxanalogblock--;
//因为没有插入新元素,回滚maxanalogblock值
count++;
} else //若数组中存在待插入元素 {
maxanalogblock--;
//因为没有插入新元素,回滚maxanalogblock值
cout<<" 第"<<x+1<<"次访问,页面"<<process[x]<<" 已存在 直接访问"<<endl;
}
}
}
//读一个序列号,输出当前数组元素
cout<<"真实物理块情况:";
for (i=0;i<mnum;i++) {
if(block[i]!=-1)
cout<<block[i]<<" ";
}
cout<<"模拟物理块情况:";
for (i=0;i<mnum;i++) {
if(analogblock[i]!=-1)
cout<<analogblock[i]<<" ";
}
cout<<endl<<"页面换算次数为:"<<count<<endl;
cout<<"置换率为:"<<(float)count/pnum<<endl;
return 0;
}
//g++ test71.cpp -o test71 -lpthread&&./test71
LRU页面置换算法:
Linux效果图(采用UOS + VScode + g++)

程序框图

C++代码(LRU):
#include<iostream>
using namespace std;
static int mnum;
//物理块数
static int pnum;
//页面走向
static int count=0;
//页面置换次数
static int *analogblock;
//模拟物理块
static int *block;
//物理块
static int *process;
//随机页面访问序列
int judge(int a[],int n,int x) //判断数组中是否已有x,若有返回其下标值,没有则返回-1 {
int i;
for (i=0;i<n;i++)
if(x==a[i])
return i;
return -1;
}
void replace(int y,int mnum,int x)//用于物理块页面置换,y是用来置换的页面,x是被置换的页面 {
int i;
for (i=0;i<mnum;i++)
if(x==block[i])
block[i]=y;
}
void move(int a[],int n,int i) //移动下标为i的元素到尾部 {
int j;
int m=a[i];
for (j=i;j<n-1;j++)
a[j]=a[j+1];
a[n-1]=m;
}
int main() {
int i;
int maxanalogblock=-1;
//模仿栈的定义
int x;
cout<<"请输入页框大小物理块数:\n";
cin>>mnum;
if(mnum>999999) {
cout<<"输入超出控制大小!"<<endl;
return 0;
}
cout<<"自动生成的内存块需求序列个数:\n";
cin>>pnum;
if(pnum>999999) {
cout<<"输入超出控制大小!"<<endl;
return 0;
}
analogblock=new int[mnum];
block=new int[mnum];
process=new int[pnum];
for (i=0;i<mnum;i++) analogblock[i]=-1;
/////////////////////
//随机产生页面走向序列
cout<<"产生随机序列如下:\n";
srand( (unsigned)time( NULL ) );
//以time函数值(即当前时间)作为种子数,保证两次产生序列的随机性
for (i=0; i<pnum; i++) {
process[i] = rand()%10;
cout<<process[i]<<" ";
}
cout<<endl;
//////////////////////
cout<<"最近最少使用(LRU)页面置换算法,结果: \n\n";
//////////////////////
for (x=0;x<pnum;x++) //自动读数 {
//读一个序列号,输出当前数组元素
cout<<"真实物理块情况:";
for (i=0;i<mnum;i++) {
if(block[i]!=-1)
cout<<block[i]<<" ";
}
cout<<"模拟物理块情况:";
for (i=0;i<mnum;i++) {
if(analogblock[i]!=-1)
cout<<analogblock[i]<<" ";
}
//////////////////////////
maxanalogblock++;
//读数后maxanalogblock自动+1
if(maxanalogblock<mnum) //若在物理块范围内 {
if(judge(analogblock,mnum,process[x])==-1)//若数组中不存在待插入元素 {
analogblock[maxanalogblock]=process[x];
//新元素从尾部插入
block[maxanalogblock]=process[x];
//新元素从尾部插入
cout<<" 第"<<x+1<<"次访问,页面"<<process[x]<<" 缺页中断 调入页面"<<process[x]<<endl;
} else //若数组中存在待插入元素 {
move(analogblock,maxanalogblock,judge(analogblock,mnum,process[x]));
//移动下标为i的元素到尾部
maxanalogblock--;
//因为没有插入新元素,回滚maxanalogblock值
cout<<" 第"<<x+1<<"次访问,页面"<<process[x]<<" 已存在 直接访问"<<endl;
}
} else //超过物理块数的元素 {
if(judge(analogblock,mnum,process[x])==-1)//若数组中不存在待插入元素 {
//栈法插入(第一个元素出,后面元素前移,新元素从尾部入)
cout<<" 第"<<x+1<<"次访问,页面"<<process[x]<<" 缺页中断 页面"<<process[x]<<"置换出页面"<<analogblock[0]<<endl;
replace(process[x],mnum,analogblock[0]);
//物理块中页面置换
for (i=0;i<mnum-1;i++)
analogblock[i]=analogblock[i+1];
analogblock[mnum-1]=process[x];
//////////////////
maxanalogblock--;
//因为没有插入新元素,回滚maxanalogblock值
count++;
} else //若数组中存在待插入元素 {
move(analogblock,mnum,judge(analogblock,mnum,process[x]));
//移动下标为i的元素到尾部
maxanalogblock--;
//因为没有插入新元素,回滚maxanalogblock值
cout<<" 第"<<x+1<<"次访问,页面"<<process[x]<<" 已存在 直接访问"<<endl;
}
}
}
//读一个序列号,输出当前数组元素
cout<<"真实物理块情况:";
for (i=0;i<mnum;i++) {
if(block[i]!=-1)
cout<<block[i]<<" ";
}
cout<<"模拟物理块情况:";
for (i=0;i<mnum;i++) {
if(analogblock[i]!=-1)
cout<<analogblock[i]<<" ";
}
cout<<endl<<"页面换算次数为:"<<count<<endl;
cout<<"置换率为:"<<(float)count/pnum<<endl;
return 0;
}
//g++ test72.cpp -o test72 -lpthread&&./test72
LFU页面置换算法:
Linux效果图(采用UOS + VScode + g++)

程序框图

C++代码(LFU):
#include<iostream>
using namespace std;
static int mnum;
//物理块数
static int pnum;
//页面走向
static int count=0;
//页面置换次数
static int **analogblock;
//模拟物理块
static int *block;
//物理块
static int *process;
//随机页面访问序列
int judge(int *a[],int n,int x) //判断数组中是否已有x,若有返回其下标值,没有则返回-1 {
int i;
for (i=0;i<n;i++)
if(x==a[i][0])
return i;
return -1;
}
void replace(int y,int mnum,int x)//用于物理块页面置换,y是用来置换的页面,x是被置换的页面 {
int i;
for (i=0;i<mnum;i++)
if(x==block[i])
block[i]=y;
}
void move(int *a[],int n,int i) //移动下标为i的元素,比较访问次数次多少进行前进 {
int j;
int m=a[i][0];
int m2=a[i][1];
for (j=i;j<n-1;j++) {
if(m2>=a[j+1][1]) {
a[j][0]=a[j+1][0];
a[j][1]=a[j+1][1];
a[j+1][0]=m;
a[j+1][1]=m2;
}
}
}
int main() {
int i;
int maxanalogblock=-1;
//模仿栈的定义
int x;
//动态数组初始化
cout<<"请输入页框大小物理块数:\n";
cin>>mnum;
if(mnum>999999) {
cout<<"输入超出控制大小!"<<endl;
return 0;
}
cout<<"自动生成的内存块需求序列个数:\n";
cin>>pnum;
if(pnum>999999) {
cout<<"输入超出控制大小!"<<endl;
return 0;
}
analogblock=(int**) (new int[mnum]);
block=new int[mnum];
process=new int[pnum];
for (i=0;i<mnum;i++) analogblock[i]=(int*) new int[2];
//用于保存页面号和访问次数
for (i = 0; i < mnum; i++) {
analogblock[i][0]=-1;
analogblock[i][1]=0;
}
/////////////////////
//随机产生页面走向序列
cout<<"产生随机序列如下:\n";
srand( (unsigned)time( NULL ) );
//以time函数值(即当前时间)作为种子数,保证两次产生序列的随机性
for (i=0; i<pnum; i++) {
process[i] = rand()%10;
cout<<process[i]<<" ";
}
cout<<endl;
//////////////////////
cout<<"最近最不常使用(LFU)页面置换算法,结果: \n\n";
//////////////////////
for (x=0;x<pnum;x++) //自动读数 {
//读一个序列号,输出当前数组元素
cout<<"真实物理块情况:";
for (i=0;i<mnum;i++) {
if(block[i]!=-1)
cout<<block[i]<<" ";
}
cout<<"模拟物理块情况:";
for (i=0;i<mnum;i++) {
if(analogblock[i][0]!=-1)
cout<<analogblock[i][0]<<" ";
//<<"访问次数"<<analogblock[i][1]<<" "
}
//////////////////////////
maxanalogblock++;
//读数后maxanalogblock自动+1
if(maxanalogblock<mnum) //若在物理块范围内 {
if(judge(analogblock,mnum,process[x])==-1)//若数组中不存在待插入元素 {
analogblock[0][0]=process[x];
//新元素从头部插入
analogblock[0][1]=1;
block[maxanalogblock]=process[x];
//新元素从尾部插入
move(analogblock,mnum,0);
//移动下标为i的元素到相同访问次数页面的顶部
cout<<" 第"<<x+1<<"次访问,页面"<<process[x]<<" 缺页中断 调入页面"<<process[x]<<endl;
} else //若数组中存在待插入元素 {
// move(analogblock,maxanalogblock,judge(analogblock,mnum,process[x]));//移动下标为i的元素到尾部
analogblock[judge(analogblock,mnum,process[x])][1]++;
move(analogblock,mnum,judge(analogblock,mnum,process[x]));
//移动下标为i的元素到相同访问次数页面的顶部
maxanalogblock--;
//因为没有插入新元素,回滚maxanalogblock值
cout<<" 第"<<x+1<<"次访问,页面"<<process[x]<<" 已存在 直接访问"<<endl;
}
} else //超过物理块数的元素 {
if(judge(analogblock,mnum,process[x])==-1)//若数组中不存在待插入元素 {
//栈法插入(新元素从头部入,替换掉头部)
cout<<" 第"<<x+1<<"次访问,页面"<<process[x]<<" 缺页中断 页面"<<process[x]<<"置换出页面"<<analogblock[0][0]<<endl;
replace(process[x],mnum,analogblock[0][0]);
//物理块中页面置换
analogblock[0][0]=process[x];
analogblock[0][1]=1;
move(analogblock,mnum,0);
//移动下标为i的元素相同访问次数页面的顶部
//////////////////
maxanalogblock--;
//因为没有插入新元素,回滚maxanalogblock值
count++;
} else //若数组中存在待插入元素 {
analogblock[judge(analogblock,mnum,process[x])][1]++;
move(analogblock,mnum,judge(analogblock,mnum,process[x]));
//移动下标为i的元素到相同访问次数页面的顶部
maxanalogblock--;
//因为没有插入新元素,回滚maxanalogblock值
cout<<" 第"<<x+1<<"次访问,页面"<<process[x]<<" 已存在 直接访问"<<endl;
}
}
}
//读一个序列号,输出当前数组元素
cout<<"真实物理块情况:";
for (i=0;i<mnum;i++) {
if(block[i]!=-1)
cout<<block[i]<<" ";
}
cout<<"模拟物理块情况:";
for (i=0;i<mnum;i++) {
if(analogblock[i][0]!=-1)
cout<<analogblock[i][0]<<" ";
}
cout<<endl<<"页面换算次数为:"<<count<<endl;
cout<<"置换率为:"<<(float)count/pnum<<endl;
return 0;
}
//g++ test73.cpp -o test73 -lpthread&&./test73