![在这里插入图片描述](https://img-blog.csdnimg.cn/ffafc7a813394c2499f696fff43d711c.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/c2ea0181379f4316b359fb1ee386ed9f.png)
易混淆词:reg(寄存器)、block/PBC(分配的物理块)、page_num/PAC(页面序列)、memory【】(页号)、count / lps/exchange_numbber(缺页次数)、table/rel【】【】(矩阵)、lpp/lack_page_rate(缺页率)、index(页面号索引)、
OPT
所选择的被换出的页面将是最长时间内不再被访问,通常可以保证获得最低的缺页率
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
int toNextPageLen[50];
//当前页面位置下一次被访问的位置,下标为当前页面位置,值为下一次访问位置
void OPT(int page_access[],int PBC,int PAC,int result[][50]){
int k = 0;
int nextPageAccessIndex[50];
//存储当前页面的位置,作为该页面上一次被访问的下一次访问位置 ,下标为页 面,值为下一次访问位置
memset(nextPageAccessIndex,0,sizeof(nextPageAccessIndex));
//初始化为0,代表没再访问过
//1.获取当前位置页面下次访问该页面的位置
for(int i = PAC-1; i>=0; i--){
int nextIndex = nextPageAccessIndex[page_access[i]];
if(nextIndex <= 0){ //没在访问过则位置设为无穷
toNextPageLen[i] = INT_MAX;
}else{
toNextPageLen[i] = nextIndex;
}
nextPageAccessIndex[page_access[i]] = i;
}
//2.计算每一次访问的每个物理块存放的当前页面
int flagBlock[50];
//存储页面是否在物理块中,用于去重,下标为页面,值为访问位置
memset(flagBlock,-1,sizeof(flagBlock));//不存在物理块中为-1
for(int i = 0 ; i < PAC; i++){ //遍历访问位置
int len = 0;//存储下一次访问该页的最大长度
int block = -1;//要替换的物理块中页面
if(flagBlock[page_access[i]]!=-1){//如果存在物理块中,直接复制前一次数据
for(int j = 0; j < k; j++){
result[j][i] = result[j][i-1];
}
flagBlock[page_access[i]] = i;
continue;
}
for(int j = 0; j < PBC; j++){ //遍历物理块
if(k < PBC){//如果当前使用的物理块数少于总共物理块数,复制上一次访问页面,在剩下的物理块中添加当前页面
if(j == k){ //如果为新的物理块,直接存储当前页面
result[k][i] = page_access[i];//存储当前页面
flagBlock[page_access[i]] = i;// 标记为存在物理块中
k++; //使用的物理块数+1
result[PBC][i] = 1; //判断是否缺页,有增加则缺页
break;
}else{//复制上一次的页面
result[j][i] = result[j][i-1];
}
}else{//如果物理块满
result[j][i] = result[j][i-1];//复制上一次页面
int s = toNextPageLen[flagBlock[result[j][i-1]]]-i;
if(len < s){//找到下次访问最长页面替换 ,即判断物理块中页面 上次的下标 的下一次访问位置减去当前位置,得到距离长度
block = j;
len = s;
}
}
}
if(block!=-1){
flagBlock[result[block][i]] = -1;
flagBlock[page_access[i]] = i;
result[block][i] = page_access[i];//替换下次访问最长的页面
result[PBC][i] = 1;
}
}
}
int main(){
int PBC;//物理块数 physical block count
int PAC;//页面访问次数 Page access count
int page_access[50];//存储访问的页面,下标代表第几次访问
int result[50][50];//0~PBC-1行0~PAC-1列代表每个物理块存储每次访问的页面,PBC行存储是否缺页,是为1,否为0
memset(result, -1, sizeof(result));
printf("请输入物理块数:");
scanf("%d",&PBC);
printf("请输入访问次数:");
scanf("%d",&PAC);
for(int i = 0 ; i < PAC; i++){
printf("请输入第%d次访问的页面:",i+1);
scanf("%d",&page_access[i]);
}
//OPT
OPT(page_access, PBC, PAC, result);
//输出
printf("\n\n页面访问\t");
for(int i = 0 ; i < PAC; i++){
printf("%d\t",page_access[i]);
}
printf("\n");
for(int i = 0; i < PBC; i++){
printf("物理块%d\t\t",i+1);
for(int j = 0; j < PAC; j++){
if(result[i][j]!=-1&&result[PBC][j]!=-1){
printf("%d\t",result[i][j]);
}else{
printf("\t");
}
}
printf("\n");
}
int lack_page_number = 0;//缺页次数
printf("是否缺页\t");
for(int i = 0; i < PAC; i++){
printf("%c\t",result[PBC][i]==1?'Y':'N');
if(result[PBC][i]==1)lack_page_number++;
}
printf("\n");
int exchange_numbber = lack_page_number - PBC;
double lack_page_rate = lack_page_number/(double)PAC;
printf("缺页次数: %d\n", lack_page_number);
printf("置换次数: %d\n",exchange_numbber);
printf("缺页率: %0.2lf%%\n",lack_page_rate) ;
}
FIFO
选择换出的页面是最先进入的页面。
该算法会将那些经常被访问的页面也被换出,从而使缺页率升高。
#include <stdio.h>
#define PAGES 12 /*页面引用页数*/
#define M 4 /*当前分配给改作业的物理块数*/
/*页面引用串*/
int page[PAGES] = {1,2,3,4,5,1,4,1,2,3,4,5};
int rel[M][PAGES]; /*存储结果数组*/
/*内存物理块结构体*/
typedef struct {
int pnum; /*该块中所存的页面号*/
int tm ; /*从最近一次调入所经历的时间*/
}PBlock;
/*初始化物理块数组*/
void init(PBlock *pb)
{
int i,j;
//pb = (PBlock*)malloc(sizeof(PBlock)*M);
for (i=0;i<M;i++){
pb[i].pnum = -1;
pb[i]. tm = -1;
for (j=0;j<PAGES;j++){
rel[i][j] = -1;
}
}
}
/*打印结果数组*/
void printRelArr( int rel[M][PAGES])
{
int i,j;
for (i=0;i<M;i++){
for (j=0;j<PAGES;j++){
if (rel[i][j]==-1)
printf ( "-1" );
else
printf ( "%d " ,rel[i][j]);
}
printf ( "\n" );
}
}
/*打印一维数组*/
void printArr1( int *arr, int n)
{
int i;
for (i=0;i<n;i++){
printf ( "%d " ,arr[i]);
}
printf ( "\n" );
}
/*查看页面号为num的页面是否在内存块中,存在返回1*/
int in_mem( int num,PBlock *pb, int m)
{
int i;
int b = 0;
for (i=0;i<m;i++){
if (pb[i].pnum == num){
b = 1;
break ;
}
}
return b;
}
int fifo(PBlock* pb, int m)
{
int lps = 0; /*缺页次数*/
double lpp; /*缺页率*/
int p = 0; /*替换指针*/
int index = 0; /*页面号索引*/
while (index < PAGES) {
if (!in_mem(page[index], pb, M)) { //如果该页面不在物理块中
pb[p].pnum = page[index]; /*将该页面放入物理块中*/
p = (p + 1) % M; /*替换指针移动*/
lps++; /*缺页次数加 1*/
for (int i = 0; i < M; i++) {
rel[i][index] = pb[i].pnum;
}
}
index++;
}
printf("FIFO算法所得缺页次数为 %d\n", lps);
lpp = (double)lps / PAGES;
printf("FIFO算法缺页率为 %0.4lf \n", lpp);
printf("页面号序列为:\n");
printArr1(page, PAGES);
printf("结果数列为:\n");
printRelArr(rel);
return 0;
}
int main()
{
//printArr(rel);
PBlock pb[M];
init(pb);
fifo(pb,M);
init(pb);
return 0;
}
LRU
虽然无法知道将来要使用的页面情况,但是可以知道过去使用页面的情况。LRU 将最近最久未使用的页面换出
#include<stdio.h>
int block_num; /*分配的物理块数*/
int page_num; /*要访问的页面序列个数*/
int page[100]; /*要访问的页面序列*/
int memory[10]; /*物理块中的页号*/
int table[100][10]; /*显示矩阵*/
int reg[10]; /*寄存器--记录页面的访问时间*/
char Que[100]; /*数组,记录是否缺页*/
int main()
{
int count=0; /*记录缺页次数*/
int i,j,k;
printf("| LRU页面置换算法 |\n");
while(1)
{
printf("请输入分配的物理块的个数(M<=10):\n");
scanf("%d",&block_num);
if(block_num>10)
printf("请重新输入");
printf("\n");
break;
}
while(1)
{
printf("输入要访问的页面序列个数(P<=100):\n");
scanf("%d",&page_num);
if(page_num>100)
printf("请重新输入");
printf("\n");
break;
}
printf("请依次输入要访问的页面序列:\n");
for(i=0;i<page_num;i++)
{
scanf("%d",&page[i]);
Que[i] = 'N';
}
for(i=0;i<block_num;i++)
memory[i]=-1; //初始内存块中默认为空,用-1表示
//访问页面
for(i=0;i<page_num;i++)
{
if(i==0) //访问的第一个页面
{
memory[i]=page[i];
reg[i]=i;
for(j=0;j<block_num;j++)
table[i][j]=memory[j];
Que[i]='Y';
count++;
}
else
{ /*判断新页面号是否在物理块中*/
for(j=0,k=0;j<block_num;j++)
{
if(memory[j]!=page[i])
k++;
else
{ /*新页面在内存块中*/
reg[j]=i; //刷新该页面的访问时间
for(int n=0;n<block_num;n++)
table[i][n]=memory[n];
}
}
}
if(k==block_num) /*新页面不在物理块中,缺页*/
{
int q=0;
Que[i]='Y';
count++;
for(int j=0;j<block_num;j++)
{
if(memory[j]==-1) /*内存块未满*/
{
memory[j]=page[i];
reg[j]=i;
for(int n=0;n<block_num;n++)
table[i][n]=memory[n];
break;
}
else
q++;
}
if(q==block_num)/*内存块已满,需采用LRU置换算法选择换出页*/
{
int min=0; //记录换出页
for(int m=1;m<block_num;m++)
if(reg[m]<reg[min])
min=m;
memory[min]=page[i];
reg[min]=i; /*记录该页的访问时间(新到的页面进入之前min的位置,需将min位置的访问时间更改)*/
for(int n=0;n<block_num;n++)
table[i][n]=memory[n];
}
}
}
/*输出运行过程及结果*/
printf("采用LRU页面置换算法结果如下: \n");
printf("\n");
printf("\n");
printf("页号:");
for(i=0;i<page_num;i++)
printf("%3d",page[i]);
printf("\n");
printf("-----------------------------------------------------\n");
for(i=0;i<block_num;i++)
{
printf("块%2d:",i);
for(j=0;j<page_num;j++)
printf("%3d",table[j][i]);
printf("\n");
}
printf("-----------------------------------------------------\n");
printf("缺页:");
for(i=0;i<page_num;i++)
printf("%3c",Que[i]);
printf("\n");
printf("-----------------------------------------------------\n");
printf("\t缺页次数:%d\n",count);
printf("\t缺页率:%d/%d\n",count,page_num);
printf("-----------------------------------------------------\n");
}