⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 os4.cpp

📁 页式虚拟存储管理中地址转换和缺页中断yeshidsdkfljwiorwoper
💻 CPP
字号:
//os4.cpp--采用FIFO的页式虚拟存储管理的地址转换和缺页中断

#include <iostream.h>
#include <iomanip.h>
#include <ctype.h>

//页表用数组模拟,在实验中页表数据结构定义为:
#define N 32 //实验中假定的页表长度,页表的长度实际上是由系统按照作业长度决定的
#define M 4	//实验中用,用固定局部置换算法给每个进程分配的主存物理块数

struct
{int  lnumber;  //页号
 int  flag;   	//表示该页是否在主存,"1"表示在主存,"0"表示不在主存
 int  pnumber;  	//该页所在主存块的块号
 int  write;   	//该页是否被修改过,"1"表示修改过,"0"表示没有修改过
 int  dnumber;  	//该页存放在磁盘上的位置,即磁盘块号
}page[N];  	//页表定义

int p[M];	//用数组模拟]FIFO算法中的队列(使用循环队列)
int head;

void initial(void);	//初始化
int do_mmap(int);	//模拟地址转换
void do_page_fault(int);	//缺页中断处理程序
void run_first_instructon(int);	//执行进程的第一条指令
void run_a_instruction(int);	//CPU执行一条指令
void print_page_and_fifoqueue(void);	//输出页表和FIFO队列

main()
{
	int laddress, paddress;	//逻辑地址,物理地址
	int lnumber, ad, pnumber;	//页号,页内地址和物理块号

	initial();	//手工初始化页表
	print_page_and_fifoqueue();	//输出页表和FIFO队列
	
	run_first_instructon(0x0000);	//运行进程的第一条指令的地址
	
	//输入下一条指令的地址
	cout<<"输入下一条指令的逻辑地址(0~32767)(-1 to end)"<<endl;
	cin>>laddress;
	while(laddress>32767){	//输入正确性检测
		cout<<"Enter ERORR! 请重新输入下一条指令的逻辑地址(0~32767)(-1 to end)"<<endl;
		cin>>laddress;
	}
	while(laddress!=-1){	//还有指令要执行
		lnumber=laddress>>10;	//取逻辑地址的页号lnumber
		if(page[lnumber].flag==1){	//指令所在的页面已装入在内存中
			paddress=do_mmap(laddress);	//形成物理地址

			cout<<paddress<<"输出转换后的物理地址"<<endl;
			run_a_instruction(paddress);	//CPU根据得到的物理地址去执行指令
			
			cout<<"此指令执行是否修改所在页面lnumber="<<lnumber<<"(y/n?) ";
			char change;
			cin>>change;
			if(tolower(change)=='y'){
				page[lnumber].write=1;	//若页面要已修改,则将此页面修改位置1
				print_page_and_fifoqueue();
			}
		}
		else{	//缺页中断
			cout<<lnumber<<"输出该页的页号--表示硬件产生缺页中断"<<endl;
			do_page_fault(lnumber);	//直接转去缺页中断处理

			continue;	//本循环结束,重新执行指令
		}

		cout<<"输入下一条指令的逻辑地址((0~32767)),-1 to end.\n";
		cin>>laddress;
		while(laddress>32767){	//输入正确性检测
			cout<<"Enter ERORR! 请重新输入下一条指令的逻辑地址(0~32767)(-1 to end)"<<endl;
			cin>>laddress;
		}
	}
	
	cout<<"祝贺,进程运行结束!"<<endl;
	system("PAUSE");
	return 0;
}

 //手工初始化页表和p[M]队列
void initial(void)
{
	int i;
	
	for(i=0; i<=31; i++){
		page[i].lnumber=i;			
		if(i<=M-1){	//预装入算法初始化页表的前四项
			cout<<"输入页号为 "<<i<<" 所在内存的物理块号(预装入前四个页面):";
			cin>>page[i].pnumber;
			page[i].flag=1;	//存在标志置1
		}
	}
	
	//初始化FIFO的队列
	head=0;
	for(i=0; i<=M-1; i++)
		p[i]=i;
}

//输出页表和FIFO队列
void print_page_and_fifoqueue(void)
{
	int i;

	cout<<"Print the page table.\n";
	cout<<setw(10)<<"lnumber"<<setw(9)<<"flag"<<setw(10)<<"pnumber"
		<<setw(10)<<"write"<<setw(10)<<"dnumber"<<endl;
	for(i=0; i<=N-1; i++)
		cout<<setw(7)<<page[i].lnumber<<setw(10)<<page[i].flag<<setw(10)<<page[i].pnumber
			<<setw(10)<<page[i].write<<setw(10)<<page[i].dnumber<<endl;

	cout<<"Print the FIFO queue.\n";
	cout<<setw(10)<<"NO"<<setw(40)<<"page(已在主存的页号lnumber)\n";
	cout<<"head="<<head<<endl;
	for(i=0; i<=M-1;i++)
		cout<<setw(10)<<i<<setw(15)<<p[i]<<endl;
}


//模拟地址转换
int do_mmap(int laddress)
{
	int lnumber, ad, pnumber, paddress;

	lnumber=laddress>>10;	//取逻辑地址的页号lnumber

	ad=laddress&0x3ff;	//页内地址
	pnumber=page[lnumber].pnumber;	//从页表中取得块号pnumber
	paddress=pnumber<<10|ad;

	return paddress;
}

//CPU执行一条指令,输出物理地址表示指令执行完成
void run_a_instruction(int paddress)
{
	cout<<paddress<<" 输出物理地址--表示指令执行完成"<<endl;
}

//执行进程的第一条指令
void run_first_instructon(int laddress)
{
	int lnumber, ad, pnumber, paddress;

	lnumber=laddress>>10;	//取逻辑地址的页号
	if(page[lnumber].flag==1)	//由于式预装入方式,所以第一条指令所在的页面肯定在内存中
			paddress=do_mmap(laddress);	//形成物理地址	
	
	cout<<paddress<<"输出转换后的物理地址"<<endl;
	run_a_instruction(paddress);

	cout<<"此指令执行(0x0000)是否修改所在页面lnumber="<<lnumber<<"(y/n?) ";
	char change;
	cin>>change;
	if(tolower(change)=='y'){	//若指令执行完时修改了页面,则置write标志位位1
		page[lnumber].write=1;
		print_page_and_fifoqueue();
	}

	cout<<"********第一条指令执行完成(地址为0x0000)***********"<<endl;
}

//页面写回磁盘
void write_to_harddisk(int j)
{
	cout<<j<<"输出已修改的淘汰的页号--表示该页写回了磁盘"<<endl;
}

//缺页中断处理程序
void do_page_fault(int lnumber)
{
	int j;	//j是选择淘汰的页

	j=p[head];
	p[head]=lnumber;	//lnumber是新装入的页号
	head=(head+1)%M;
	
	//若淘汰出主存的页j已修改,则写会磁盘
	if(page[j].write==1)
		write_to_harddisk(j);	//页j写回磁盘

	//修改页表
	page[j].flag=0;	//页表中第j页的存在标志为0
	page[lnumber].flag=1;	//页表第lnumber的存在标志为1
	page[lnumber].write=0;	//页表第lnumber的修改标志为0
	page[lnumber].pnumber=page[j].pnumber;	//第拉怒目布尔页的主存块号为第j页原主存块号

	cout<<lnumber<<"输出该页--表示该页调入了主存"<<endl;
	cout<<"按任意键将查看“页面置换”之后的页表page[N]和FIFO队列信息"<<endl;
	system("PAUSE");
	print_page_and_fifoqueue();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -