您的位置:首页 > 其它

《操作系统》实验之虚拟存储管理

2015-07-13 17:53 232 查看

实验内容:

<一>

第一部分:模拟请求分页虚拟存储管理技术中的硬件地址变换和缺页中断的过程

提示:

1、 请求分页虚拟存储管理技术是把作业地址空间的全部信息存放在磁盘上,当作业被选中运行时,先把作业的开始几页装入主存并启动运行.为此,在为作业建立页表时,应说明哪些页已在内存,哪些页不在内存.

页表的格式如下:

页号

标志

主存块号

外存地址

其中,”标志”表示对应页是否已装入主存

0:表示对应页已装入主存

1:表示对应页未装入主存

“主存块号”表示该页对应的主存块的块号

“外存地址”表示该页所在的外存物理

2、 作业在执行时,指令中的逻辑地址指出参加运算操作数(或指令)地址中的页号和页内偏移量.硬件地址转换机构按页号查页表.

若该页的标志为”1”,则表示该页已在主存,从而找到该页对应的内存块号,根据关系式:

绝对地址=块号*块的长度+页内偏移量

计算出欲访问的内存地址.由于页长为2的整次幂,所以只要将块号与页内偏移量相拼接,放入地址寄存器即可按照该地址取指令或取操作数,完成指定的操作.

若对应的页不在内存(即标志为0),则硬件产生缺页中断,转操作系统处理系统.根据页表中的”外存地址”,找到该页.再查内存分块表,找一个空闲块装入该页,修改页表和内存分块表,继续执行被中断的指令.

3、 设计一个”地址变换”程序,模拟硬件地址变换过程:

当访问的页在内存时,则形成绝对地址后,不去模拟指令的执行,而是输出被转换的地址;当访问的页不在内存时,则输出*该页(页号)不在内存,以表示产生了一次缺页中断;若地址非法,显示地址非法,并终止程序的运行.



假定内存的每块长度为128字节,现有一个只有七页的作业,其中第0页至第3页已经装入内存.该作业的页表如下:

页号

标志

内存块号

外存地址

修改值

0

1

5

011

1

1

1

8

012

1

2

1

9

013

0

3

1

1

021

0

4

0

022

5

0

023

6

0

121

作业执行的指令序列如下表:

操作

页号

单元号(八进制)

操作

页号

单元号(八进制)

+

0

070

移位

4

053

+

1

050

+

5

023

*

2

015



1

037



3

021



2

076



0

057

+

4

001

-

6

040



6

084

运行你设计的地址变换程序,显示或打印运行结果.因为只是模拟地址变换,并不模拟指令的执行,故不考虑上述指令的操作结果.

第二部分:采用先进先出(或LRU)算法,实现分页管理的缺页调度.

提示:

1、 在分页虚拟存储系统中,当硬件发出缺页中断时,若内存中已无空闲块,当采用FIFO算法时,则淘汰最先进入内存的页,若该页修改过,还要存入磁盘,然后,再把当前要访问的页装入该块,并修改表中的对应标志.

2、 当采用LRU算法时,则淘汰最近很少访问的页.

两算法均可采用一个数组或链表记录内存中页号的排序,每次将链首页淘汰.数组或链表中只包含页的虚页号─项信息,其它信息通过查页表得到.





实现:

实现的算法是LRU算法,模拟了硬件地址变换和缺页中断过程。

运行结果:





















源代码:

/*
* 该程序使用了位图LRU置换算法
*/

#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;

//宏定义
#define PAGE_TABLE_SIZE 10    //页表大小
#define BITMAP_SIZE    10    //位图大小。块大小为128B,则内存大小:10*128B = 1280B
#define BLOCK_SIZE 128    //块大小为128B

//结构体
struct Page{    //页
bool flag;                //标志,是否存入内存
unsigned short blockNo;    //主存块号
unsigned short addr;    //外村地址
bool isMod;                //修改位
};

struct JobWork{    //作业指令
char operation[5];    //操作名称
unsigned short PageNo;    //页号
unsigned short UnitNo;    //单元号
};

struct LRUNode{    //LRU链表节点
unsigned short PageNo;    //页号
LRUNode *next;        //指向下一个节点的指针
};

//局部变量
Page PageTable[PAGE_TABLE_SIZE];    //定义页表
bool BitMap[BITMAP_SIZE];    //定义内存位图
JobWork work[20];    //作业执行的指令序列

int PageTableNum;    //当前页表大小
int workNum;        //当前作业指令集大小

LRUNode *LRUqueue;    //LRU(最近最久未使用算法)队列

//局部函数
void Init();    //初始化,页表,位图等
unsigned short GetAddr(unsigned short curPage,unsigned short UnitNo);    //输入 页号和页内偏移,得到绝对地址
void Insert(unsigned short page);    //将最近使用的页插入到LRU队列中 或 在LRU队列中调整位置,使其始终保持最近最久未使用的页表节点在前面
int FindFreeBlock();        //在内存中查找空闲块
void DropLRUHead();            //丢弃掉LRU队列的第一个结点
void DisplayPageTable();    //打印页表
void DisplayLRUQueue();        //打印LRU队列

//主函数
int main()
{
int i;
Init();    //初始化

printf("初始页表:\n");
DisplayPageTable();
printf("\n");
printf("初始LRU队列:\n");
DisplayLRUQueue();
printf("\n");

for(i=0;i<workNum;i++){    //模拟取指令
printf("-------------------- 第%d条指令:%s -----------------------\n",i+1,work[i].operation);
printf("取指令\n");

unsigned short curPage = work[i].PageNo;    //取该指令页号
printf("取出页号:%d\n",curPage);

//判断地址是否非法
if(curPage<0 || curPage>PageTableNum){    //页号非法
printf(" 访问地址非法\n");
return 0;
}
if(work[i].UnitNo<0 || work[i].UnitNo>=BLOCK_SIZE){    //页内偏移地址非法
printf(" 访问地址非法\n");
return 0;
}

//判断该页是否在内存
while( PageTable[curPage].flag!=1 ){
printf(" 该页不在内存\n");
printf(" 发出缺页中断\n");
int freeBlock = -1;
if( (freeBlock = FindFreeBlock())==-1 ){    //找内存中的空闲块。
printf(" 没有在内存中找到空闲块,调用LRU页面置换算法\n");

unsigned short dropPage = LRUqueue->next->PageNo;    //被淘汰的页号
printf("  获得被淘汰的页号(%d)\n",dropPage);

if( PageTable[dropPage].isMod==1 ){    //该页修改过
printf("   该页修改过,将该页调到磁盘");
PageTable[dropPage].isMod = 0;
}

printf("  丢弃该页\n");
PageTable[dropPage].flag = 0;
DropLRUHead();    //丢弃掉LRU队列的第一个结点
unsigned short dropBlock = PageTable[dropPage].blockNo;
PageTable[dropPage].blockNo = -1;

printf("  调进页(%d)到内存\n",curPage);
Insert(curPage);
PageTable[curPage].flag = 1;
PageTable[curPage].blockNo = dropBlock;
}
else{    //找到空闲块
//在页表中找到页号对应的页,修改标志位,赋给它内存块号

printf("  在内存中找到空闲块,赋给给相应的页\n");
PageTable[curPage].blockNo = freeBlock;
PageTable[curPage].flag = 1;
BitMap[freeBlock] = 1;
Insert(curPage);
}

}
//该页在内存,形成并输出绝对地址
printf(" 该页在内存中\n");
unsigned short absAddr = GetAddr(curPage,work[i].UnitNo);    //输入 页号和页内偏移,得到绝对地址
Insert(curPage);    //调整内存页排序表(LRU队列)

if( strcmp(work[i].operation,"存")==0 ){
//如果是存指令
printf("  是存指令,置该页的修改位为 1\n");
PageTable[curPage].isMod = 1;
}

printf("绝对地址为:0x%04X\n",absAddr);
printf("\n");
printf("当前页表:\n");
DisplayPageTable();
printf("\n");
printf("当前LRU队列:\n");
DisplayLRUQueue();
printf("-----------------------------------------------------------\n");
printf("\n");

}
return 0;
}

//函数实现
void Insert(unsigned short page)    //将最近使用的页插入到LRU队列中 或 在LRU队列中调整位置,使其始终保持最近最久未使用的页表节点在前面
{
//查找链表,如果找到page,将代表该page的节点移到链表最后,说明刚刚使用过该页
LRUNode *p = LRUqueue;
while(p->next!=NULL){
if(p->next->PageNo==page){
//找到该节点,将其移动到LRU链表最后
LRUNode *t = p->next;
p->next = t->next;
while(p->next!=NULL){
p = p->next;
}
p->next = t;
t->next = NULL;
return ;
}
p = p->next;
}
//如果没有找到page,则创建一个代表该page的节点,加入到LRU链表最后
if(p->PageNo!=page){
LRUNode* t = new LRUNode;    //创建节点
t->PageNo = page;
t->next = NULL;
p->next = t;
}
//最后一个节点是page的情况不用考虑,因为它本身就在最后,不用移位
return ;
}

void Init()    //初始化,页表,位图等
{
memset(PageTable,0,sizeof(PageTable));
memset(BitMap,0,sizeof(BitMap));
PageTableNum = 0;
workNum = 0;
LRUqueue = new LRUNode;
LRUqueue->next = NULL;

//初始化页表
PageTable[0].flag = 1;
PageTable[0].blockNo = 5;
PageTable[0].addr = 0x0011;
PageTable[0].isMod = 1;
Insert(0);
PageTableNum++;

PageTable[1].flag = 1;
PageTable[1].blockNo = 8;
PageTable[1].addr = 0x0012;
PageTable[1].isMod = 1;
Insert(1);
PageTableNum++;

PageTable[2].flag = 1;
PageTable[2].blockNo = 9;
PageTable[2].addr = 0x0013;
PageTable[2].isMod = 0;
Insert(2);
PageTableNum++;

PageTable[3].flag = 1;
PageTable[3].blockNo = 1;
PageTable[3].addr = 0x0021;
PageTable[3].isMod = 0;
Insert(3);
PageTableNum++;

PageTable[4].flag = 0;
PageTable[4].blockNo = -1;
PageTable[4].addr = 0x0022;
PageTable[4].isMod = 0;
PageTableNum++;

PageTable[5].flag = 0;
PageTable[5].blockNo = -1;
PageTable[5].addr = 0x0023;
PageTable[5].isMod = 0;
PageTableNum++;

PageTable[6].flag = 0;
PageTable[6].blockNo = -1;
PageTable[6].addr = 0x0121;
PageTable[6].isMod = 0;
PageTableNum++;

//初始化作业
strcpy(work[0].operation,"+");
work[0].PageNo = 0;
work[0].UnitNo = 070;
workNum++;

strcpy(work[1].operation,"+");
work[1].PageNo = 1;
work[1].UnitNo = 050;
workNum++;

strcpy(work[2].operation,"*");
work[2].PageNo = 2;
work[2].UnitNo = 015;
workNum++;

strcpy(work[3].operation,"存");
work[3].PageNo = 3;
work[3].UnitNo = 021;
workNum++;

strcpy(work[4].operation,"取");
work[4].PageNo = 0;
work[4].UnitNo = 057;
workNum++;

strcpy(work[5].operation,"-");
work[5].PageNo = 6;
work[5].UnitNo = 040;
workNum++;

strcpy(work[6].operation,"移位");
work[6].PageNo = 4;
work[6].UnitNo = 053;
workNum++;

strcpy(work[7].operation,"+");
work[7].PageNo = 5;
work[7].UnitNo = 023;
workNum++;

strcpy(work[8].operation,"存");
work[8].PageNo = 1;
work[8].UnitNo = 037;
workNum++;

strcpy(work[9].operation,"取");
work[9].PageNo = 2;
work[9].UnitNo = 076;
workNum++;

strcpy(work[10].operation,"+");
work[10].PageNo = 4;
work[10].UnitNo = 001;
workNum++;

strcpy(work[11].operation,"取");
work[11].PageNo = 6;
work[11].UnitNo = 074;
workNum++;

//将剩余的内存置为非空,即预先设定内存没有空闲位
int i;
for(i=0;i<BITMAP_SIZE;i++){
if(!BitMap[i])
BitMap[i] = 1;
}

return ;
}

unsigned short GetAddr(unsigned short curPage,unsigned short UnitNo)    //输入 页号和页内偏移,得到绝对地址
{
unsigned short absAddr = 0;    //结果

unsigned short curBlock = PageTable[curPage].blockNo;    //取块号
absAddr = curBlock*BLOCK_SIZE + UnitNo;

return absAddr;
}

int FindFreeBlock()        //在内存中查找空闲块
{
int i;
for(i=0;i<BITMAP_SIZE;i++){
if(BitMap[i]==0){    //找到空闲块,返回块号
return i;
}
}
return -1;    //没找到
}

void DropLRUHead()                    //丢弃掉LRU队列的第一个结点
{
LRUNode *t = LRUqueue->next;
LRUqueue->next = t->next;
free(t);
}

void DisplayPageTable()    //打印页表
{
int i;
printf("页号\t标志\t内存块号\t外存地址\t修改值\n");
for(i=0;i<PageTableNum;i++){
printf("%d\t",i);
printf("%d\t",PageTable[i].flag);
if(PageTable[i].blockNo==65535){
printf("-\t\t");
}
else{
printf("%d\t\t",PageTable[i].blockNo);
}
printf("0x%03x\t\t",PageTable[i].addr);
printf("%d\n",PageTable[i].isMod);
}
return ;
}

void DisplayLRUQueue()        //打印LRU队列
{
LRUNode *q = LRUqueue->next;
while(q!=NULL){
if(q->next==NULL)
printf("%d\n",q->PageNo);
else
printf("%d->",q->PageNo);
q = q->next;
}
}


Freecode : www.cnblogs.com/yym2013
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: