武汉轻工大学实验三页式虚拟存储管理页面置换算法.docx
《武汉轻工大学实验三页式虚拟存储管理页面置换算法.docx》由会员分享,可在线阅读,更多相关《武汉轻工大学实验三页式虚拟存储管理页面置换算法.docx(17页珍藏版)》请在冰豆网上搜索。
武汉轻工大学实验三页式虚拟存储管理页面置换算法
武汉轻工大学
数学与计算机学院
《操作系统》实验报告
题目:
页式虚拟存储管理页面置换算法
专业:
数学与计算机学院
班级:
计算机类1303班
学号:
**********
***********************************
*********************************
2015年05月26日
1、目的和要求
存储管理的主要功能之一是合理的分配空间。
请求页式管理是一种常用的虚拟存储管理技术。
本实验的目的是:
通过编写和调试请求页式存储管理中页面置换算法的模拟程序以加深对存储管理方案的理解,了解虚拟存储技术的特点,掌握请求页式存储管理的页面置换方法。
2、实验内容
阅读教材《计算机操作系统》第五章,掌握存储器管理相关概念和原理。
编写程序模拟实现页式虚拟存储管理的最佳页面置换算法。
前提:
(1)页面分配采用固定分配局部置换。
(2)作业的页面走向和分得的物理块数预先指定。
可以从键盘输入也可以从文件读入。
(3)置换算法的置换过程输出可以在显示器上也可以存放在文件中,但必须清晰可读,便于检验。
3、实验环境
Windows操作系统、VC++6.0
C语言
4、设计思想
1.常量及变量
#definetotal_instruction320//指令流长
#definetotal_vp32//虚页长
#defineclear_period50//清周期
pfc_typepfc[total_vp],//主存区页面控制结构数组
pfc_type*freepf_head,//主存区页面控制结构的空闲页面头指针
pfc_type*busypf_head,//主存区页面控制结构的忙页面头指针
pfc_type*busypf_tail;//主存区页面控制结构的忙页面尾指针
intdiseffect;//页错误计数器,初次把页面载入主存时也当做页错误
pl_typepl[total_vp];//页面结构数组
2.数据结构
typedefstruct//页面结构
{
intpn,//页面序号
pfn,//页面所在内存区的帧号
counter,//单位时间内访问次数
time;//上次访问的时间
}pl_type;
structpfc_struct{//页面控制结构,模拟内存中的页集
intpn,//页面号
pfn;//内存区页面的帧号
structpfc_struct*next;//页面指针,用于维护内存缓冲区的链式结构
};
5、源程序
#include
#include
#include
#ifndef_UNISTD_H
#define_UNISTD_H
#include
#include
#endif
#defineTRUE1
#defineFALSE0
#defineINVALID-1
#definetotal_instruction320//指令流长
#definetotal_vp32//虚页长
#defineclear_period50//清周期
typedefstruct//页面结构
{
intpn,//页面序号
pfn,//页面所在内存区的帧号
counter,//单位时间内访问次数
time;//上次访问的时间
}pl_type;
pl_typepl[total_vp];//页面结构数组
structpfc_struct{//页面控制结构
intpn,//页面号
pfn;//内存区页面的帧号
structpfc_struct*next;//页面指针,用于维护内存缓冲区的链式结构
};
typedefstructpfc_structpfc_type;//主存区页面控制结构别名
pfc_typepfc[total_vp],//主存区页面控制结构数组
*freepf_head,//主存区页面控制结构的空闲页面头指针
*busypf_head,//主存区页面控制结构的忙页面头指针
*busypf_tail;//主存区页面控制结构的忙页面尾指针
intdiseffect;//页错误计数器,初次把页面载入主存时也当做页错误
inta[total_instruction];//随即指令流数组
intpage[total_instruction];//指令对应的页面号
intoffset[total_instruction];//指令所在页面中的偏移量
intinitialize(int);//初始化页面结构数组和页面控制结构数组
intFIFO(int);//先进先出算法
intLRU(int);//最近最久未使用算法
intOPT(int);//最佳置换算法
intCLOCK(int);//简单时钟(钟表)算法
intmain()
{
ints;//随机数
inti;
srand(10*getpid());/*每次运行时进程号不同,用来作为初始化随机数队列的"种子"*/
s=(int)((float)(total_instruction-1)*(rand()/(RAND_MAX+1.0)));
printf("\n------------随机产生指令流------------\n");
for(i=0;i{
a[i]=s;//任选一指令访问点m
a[i+1]=a[i]+1;//顺序执行一条指令
a[i+2]=(int)((float)a[i]*(rand()/(RAND_MAX+1.0)));//执行前地址指令m'
a[i+3]=a[i+2]+1;//顺序执行一条指令
printf("%6d%6d%6d%6d\n",a[i],a[i+1],a[i+2],a[i+3]);
s=(int)((float)((total_instruction-1)-a[i+2])*(rand()/(RAND_MAX+1.0)))+a[i+2];
}
printf("--------------------------------------\n");
for(i=0;i{
page[i]=a[i]/10;
offset[i]=a[i]%10;
}
printf("\n--不同页面工作区各种替换策略的命中率表--\n");
printf("Page\tFIFO\tLRU\tOPT\tCLOCK\n");
for(i=4;i<=32;i++)//用户内存工作区从个页面到个页面
{
printf("%2d\t",i);
FIFO(i);
LRU(i);
OPT(i);
CLOCK(i);
printf("\n");
}
return0;
}
//初始化页面结构数组和页面控制结构数组
//total_pf;用户进程的内存页面数
intinitialize(inttotal_pf)
{
inti;
diseffect=0;
for(i=0;i{
pl[i].pn=i;
pl[i].pfn=INVALID;//置页面所在主存区的帧号为-1.表示该页不在主存中
pl[i].counter=0;//置页面结构中的访问次数为
pl[i].time=-1;//置页面结构中的上次访问的时间为-1
}
for(i=0;i{
pfc[i].next=&pfc[i+1];//建立pfc[i-1]和pfc[i]之间的链接
pfc[i].pfn=i;//初始化主存区页面的帧号
}
pfc[total_pf-1].next=NULL;
pfc[total_pf-1].pfn=total_pf-1;
freepf_head=&pfc[0];//主存区页面控制结构的空闲页面头指针指向pfc[0]
return0;
}
//最近最久未使用算法
//inttotal_pf;用户进程的内存页面数
intLRU(inttotal_pf)
{
intMinT;//最小的访问时间,即很久没被访问过
intMinPn;//拥有最小的访问时间的页的页号
inti,j;
intCurrentTime;//系统当前时间
initialize(total_pf);//初始化页面结构数组和页面控制结构数组
CurrentTime=0;
diseffect=0;
for(i=0;i{
if(pl[page[i]].pfn==INVALID)//页面失效
{
diseffect++;//页错误次数加
if(freepf_head==NULL)//无空闲页面
{
MinT=100000;
for(j=0;jif(MinT>pl[j].time&&pl[j].pfn!
=INVALID)
{
MinT=pl[j].time;
MinPn=j;
}
}
freepf_head=&pfc[pl[MinPn].pfn];//最久没被访问过的页被释放
pl[MinPn].pfn=INVALID;//最久没被访问过的页被换出主存
pl[MinPn].time=-1;//最久没被访问过的页的访问时间置为无效
freepf_head->next=NULL;
}
pl[page[i]].pfn=freepf_head->pfn;//有空闲页面,把相应的页面换入主存,并把pfn改为相应的帧号
pl[page[i]].time=CurrentTime;//令访问时间为当前系统时间
freepf_head=freepf_head->next;//减少一个空闲页面
}
else
pl[page[i]].time=CurrentTime;//命中则刷新该单元的访问时间
CurrentTime++;//系统当前时间加
}
printf("%6.3f\t",1-(float)diseffect/320);
return0;
}
//最佳置换算法
//inttotal_pf;用户进程的内存页面数
intOPT(inttotal_pf)
{
inti,j;
intMaxD;//将来最近一次访问的距离的最大值(以时间单元度量)
intMaxPn;//将来最近一次访问的距离的最大值的页号
intdis;//距离计数器
intdist[total_vp];//距离数组,保存距离上一次访问的时间差距个数
initialize(total_pf);//初始化页面结构数组和页面控制结构数组
diseffect=0;
for(i=0;i{
if(pl[page[i]].pfn==INVALID)//页面失效
{
diseffect++;//页错误次数加
if(freepf_head==NULL)//无空闲页面
{
for(j=0;j{
if(pl[j].pfn!
=INVALID)//如果该页在主存中
dist[j]=100000;//该页关联的距离值改为最大值
else
dist[j]=0;//如果不在该页主存中,该页关联的距离值改为
}
dis=1;//初始距离值为
for(j=i+1;j{
if(pl[page[j]].pfn!
=INVALID&&pl[page[j]].counter==0)//如果该页在主存中,并且是将要最近访问的页
//if(pl[page[j]].pfn!
=INVALID&&dist[page[j]]==100000)//此条语句原理与上相同
{dist[page[j]]=dis;//距离值改为dis
pl[page[j]].counter=1;//使访问次数标志加,区别第一次访问和第二次访问
}
dis++;
}
MaxD=-1;
for(j=0;j{
pl[j].counter=0;//重置访问次数为
if(MaxD{
MaxD=dist[j];
MaxPn=j;
}
}
freepf_head=&pfc[pl[MaxPn].pfn];//替换将来一段时间最久访问的页
freepf_head->next=NULL;
pl[MaxPn].pfn=INVALID;
}
pl[page[i]].pfn=freepf_head->pfn;//把当前页换入主存中,并且把当前页的pfn改为换入页的帧号,
freepf_head=freepf_head->next;//减少一个空闲页面
}//if
}//for
printf("%6.3f\t",1-(float)diseffect/320);
return0;
}
//inttotal_pf;用户进程的内存页面数
intCLOCK(inttotal_pf)
{
inti;
intuse[total_vp];//使用位
intswap;
swap=0;//发生替换
initialize(total_pf);
pfc_type*pnext;//时钟指针
pfc_type*head;//队列头指针
pnext=freepf_head;
head=freepf_head;
for(i=0;idiseffect=0;
for(i=0;i{
if(pl[page[i]].pfn==INVALID)//页面失效,不在主存中
{
diseffect++;//页错误次数加
if(freepf_head==NULL)//无空闲页面
{
while(use[pnext->pfn]==1)//若时钟指针指向的页的
{
use[pnext->pfn]=0;
pnext=pnext->next;
if(pnext==NULL)pnext=head;//如果时钟指针到达队
}
//换出被替换的页
pl[pnext->pn].pfn=INVALID;
swap=1;
}
if(use[pnext->pfn]==0){//如果使用位为,则换入相应的页
pl[page[i]].pfn=pnext->pfn;//页面结构中要标记帧号
pnext->pn=page[i];//页面控制结构中要标记
use[pnext->pfn]=1;//重置使用位为
pnext=pnext->next;//时钟指针下移
if(pnext==NULL)pnext=head;//如果时钟指针到达队列
if(swap==0){freepf_head=freepf_head->next;}
}
}else{//页面在主存中
use[pl[page[i]].pfn]=1;//刷新使用位为
}
}
printf("%6.3f\t",1-(float)diseffect/320);
return0;
}
intFIFO(inttotal_pf)
{
inti;
intuse[total_vp];
intswap=0;
initialize(total_pf);
pfc_type*pnext,*head;
pnext=freepf_head;
head=freepf_head;
for(i=0;idiseffect=0;
for(i=0;i{
if(pl[page[i]].pfn==INVALID)//页面失效,不在主存中
{
diseffect++;
if(freepf_head==NULL)//无空闲页面
{
while(use[pnext->pfn]==1)
{
use[pnext->pfn]=0;
pnext=pnext->next;
if(pnext==NULL)pnext=head;
}
//换出被替换的页
pl[pnext->pn].pfn=INVALID;
swap=1;
}
if(use[pnext->pfn]==0){//如果使用位为,则换入相应的页
pl[page[i]].pfn=pnext->pfn;//页面结构中要标记帧号
pnext->pn=page[i];//页面控制结构中要标记
use[pnext->pfn]=1;//重置使用位为
pnext=pnext->next;
if(pnext==NULL)pnext=head;
if(swap==0){freepf_head=freepf_head->next;}
}
}
}
printf("%6.3f\t",1-(float)diseffect/320);
return0;
}
6、实例运行结果
7、总结
此次实验借助于老师提供的主函数main模板,只需要写FIFO,LRU,OPT,CLOCK等4个替换算法,所以阻力没那么大。
每个替换算法必须弄懂其中的细节,写起来才得心应手。
一开始做这个实验时,首先是看书,先把书上的替换算法知识点弄明白,要明白各种算法的优缺点和相互之间衍生互补关系。
这四个算法中,难以实现的是LRU算法,因为它涉及到访问时间的计算,而且它的开销也比较大。
OPT算法次难,它需要计算最近访问时间,并替换最近访问时间最大的页。
而FIFO和CLOCK实现起来比较容易,FIFO算法的实现和CLOCK算法的实现很相似,FIFO可视为CLOCK的退化版。
我先写了CLOCK算法,再删去一些约束条件就退化为FIFO算法。
这就是两者的相同之处。
理论上,CLOCK算法需要维持一个循环的主存缓冲区,需要一个循环队列去实现,并且,FIFO算法保持先进先出,因此需要一个先进先出队列。
但是,我实现这两个算法只用到了单向链表的数据结构,剩下的由其中的指针去把握了。
因此,必须对指针使用有敏锐的感觉。