C语言模拟实现虚拟存储管理(请求分页存储管理)

C语言模拟实现虚拟存储管理(请求分页存储管理)使用FIFO算法
1)实验目的
2)实验内容
3)实验基本原理和解决方案
4)数据结构、模块划分
5)画出程序的基本结构框图和流程图(包括主程序流程图、模块详细设计流程图等),对程序的每一部分要有详细的设计分析说明,说明设计实现所用的原理。
6)源代码,要求格式规范,适当加注释,以有助于说明问题为宜,注释不少于三分之一。
7)运行的结果,要求有对结果的分析
8)参考资料
一、实验目的
存储管理的主要功能之一是合理的分配空间。请求分页存储管理是一种常用的虚拟存储管理技术。本实验的目的是:通过编程模拟实现请求分页存储管理中硬件地址转换过程、缺页中断处理过程,以及先进先出页面置换算法,加深对页式虚拟存储管理的理解,了解虚拟存储技术的特点,掌握请求页式存储管理的页面置换方法;通过编写和调试地址转换过程的模拟程序以加强对地址转换过程的了解。

二、实验内容
阅读教材《计算机操作系统》第四章,掌握存储器管理相关概念和原理。
(1)用C语言实现对分页式存储管理中的硬件的地址转换和产生缺页中断。
(2)设计页表。
页式虚拟存储系统是把作业的副本存放在磁盘上,当作业被选中时,可把作业的开始几页先装入主存且启动执行。为此,在为作业建立页表时,应说明哪些页已在主存,哪些页尚未装入主存,页表的格式为:
页 号 标志 主存块号 修改标志 在磁盘上的位置

其中:
标志——用来表示对应页是否已经装入主存,标志位=1,则表示该页已经在主存中,标志位=0,则表示该页尚未装入主存。
主存块号——用来表示已经装入主存的页所占的物理块号。
修改标志——用来表示已经装入主存的页是否被修改过。为,则表示该页装入主存后被修改过;为0,则表示该页该页装入主存后未被修改过。
在磁盘上的位置——用来指出作业副本的每一页被存放在磁盘上的位置。
可根据页面置换算法的不同,页表的内容可以作适当的增删。

三、实验基本原理和解决方案
(1)地址计算。
作业执行时,先根据指令中的逻辑地址算出参加运算的操作数存放的页号和页内地址,硬件的地址转换机构按页号查页表,若该页对应标志为“1”,则表示该页已在主存,根据关系式:
绝对地址=块号*块长+页内地址
计算出欲访问的主存单元地址。按计算出的绝对地址可以取到操作数,完成一条指令的执行。若访问的页标志为“0”,则表示该页不在主存,这时硬件发“缺页中断”信号,由OS按该页在磁盘上的位置,把该页信息从磁盘读出装入主存后再重新执行这条指令。
(2)设计“地址转换”程序模拟硬件的地址转换工作。
当访问的页在主存时,则形成绝对地址,但不去模拟指令的执行,而用输出转换后的地址来代替一条指令的执行。当访问的页不在主存时,则输出“*该页页号”,表示产生了一次缺页中断,执行缺页中断程序。该模拟程序的算法如下图所示。

地址转换模拟流程图
(3) 缺页中断模拟。
在页式虚拟存储系统中,当硬件发出缺页中断请求后,引起操作系统来处理这个中断事件。如果主存有空闲物理块,则调入该页并修改页表;如果主存中没有空闲物理块,则可用FIFO页面置换算法或者LRU页面置换算法从该作业中在主存的页面中选一页淘汰,被淘汰的页是否需要重新写回磁盘,由修改标志决定。然后再把当前要访问的页装入该块。调出和装入后都要修改页表中的相应信息。
四、数据结构、模块划分
(1)存放页表的结构体
struct info //页表信息结构体
{
int pageno;
int flag; //页标志,1表示该页已在主存,0表示该页不在主存
int block; //块号
char disk[10]; //在磁盘上的位置
int dirty; //更新标志(修改标志)

}pagelist[SizeOfPage];
(2)存放操作数、逻辑地址以及页表信息的结构体
struct work{
char operands[10];
long adress;
int pagenum; //页号
int page_local;//页内地址
int sign; //标志
int Block;
int page_adress;//物理地址
int page_out; //淘汰页号
int page_back;

}worklist[12];

(3)使用数组进行模拟分配的三个物理块,po始终指向最先进去的页号,模拟FIFO算法
long po=0; //队列标记
long P[M]={0,1,2}; //假设内存中最多允许M=3个页面
(4)使用文本文件进行内存空间初始化
存放操作数文本文件:
C语言模拟实现虚拟存储管理(请求分页存储管理)_第1张图片
存放页表信息文本文件:
C语言模拟实现虚拟存储管理(请求分页存储管理)_第2张图片
void init_ex1() //内存空间初始化。
{
FILE *fp = fopen(“page.txt”,“r”), *fq = fopen(“task.txt”,“r”);
int i = 0;
int a = 0, b = 0, c=0, d=0;
char e[10];
while(fscanf(fp,"%d%d%d%d%s",&a,&b,&c,&d,&e)!=EOF)
{
pagelist[i].pageno=a;
pagelist[i].flag=b;
pagelist[i].block=c;
pagelist[i].dirty=d;
strcpy(pagelist[i].disk, e);
i++;
}
char s[10];
long n = 0;
int k=0;
while(fscanf(fq,"%s%ld",&s,&n)!=EOF)
{
if(k >= 12)
break;
strcpy(worklist[k].operands, s);
worklist[k].adress=n;
k++;
}

fclose(fp);
fclose(fq);

}
(5)输出函数
void print()
{
/* char operands[10];
long adress;
int pagenum; //页号
int page_local;//页内地址
int sign; //标志
int Block;
int page_adress;//物理地址
int page_out; //淘汰页号
int page_back; //是否写回
*/
printf(“以下数据1表示是,0表示否\n”);
printf(“操作数\t逻辑地址\t页号\t页内地址\t是否命中\t物理块号\t物理地址\t淘汰页号\t是否写回\n”);
for(int i=0;i<12;i++)
{
printf("%s\t%ld\t\t%d\t%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d",worklist[i].operands,worklist[i].adress,worklist[i].pagenum,worklist[i].page_local,worklist[i].sign,worklist[i].Block,worklist[i].page_adress,worklist[i].page_out,worklist[i].page_back);
printf("\n");
}
}

(6)模拟FIFO页面调度算法
void work_FIFO()
{
int i,j;
for(i=0;i<12;i++)
{
worklist[i].pagenum=worklist[i].adress / 128;
worklist[i].page_local=worklist[i].adress % 128;
worklist[i].page_back = 0;

	for(j=0;j<7;j++)
	{
		if(pagelist[j].pageno == worklist[i].pagenum)
		{
			if(pagelist[j].flag==1)
			{
				worklist[i].Block = pagelist[pagelist[j].pageno].block;
				worklist[i].sign=1;
				worklist[i].page_adress=(pagelist[pagelist[j].pageno].block* SizeOfBlock + worklist[i].page_local);//worklist[i].Block
				worklist[i].page_out=-1;
				if(!(strcmp(worklist[i].operands,"存")))
				{
					pagelist[worklist[i].pagenum].dirty = 1;		//是否写回磁盘,修改页表
					worklist[i].page_back = 1;
				}

				
			}
			else
			{
				//printf("*%d\n",worklist[i].pagenum);
				pagelist[P[po]].flag=0;   //将flag标志位置0,表示当前页面已被置换出去
				worklist[i].page_out=P[po];
				worklist[i].Block=pagelist[P[po]].block;
				pagelist[j].block=pagelist[P[po]].block;
				worklist[i].page_adress=(worklist[i].Block*SizeOfBlock+worklist[i].page_local);
		   	  
			   pagelist[j].flag=1;
			   worklist[i].sign=0;
			   P[po]=pagelist[j].pageno;   //保存当前页面所在的位置
			   po=(po+1)%M; 

			   if(!(strcmp(worklist[i].operands,"存")))
				{
					pagelist[worklist[i].pagenum].dirty = 1;		//是否写回磁盘,修改页表
					worklist[i].page_back = 1;
				}

			}
		}
		else
		{
			continue;
		}
	}

}

}
(7)主函数
int main()
{
init_ex1();
work_FIFO();
print();
return 0;
}
五、画出程序的基本结构框图和流程图(包括主程序流程图、模块详细设计流程图等),对程序的每一部分要有详细的设计分析说明,说明设计实现所用的原理。
main()函数

init_ex1()函数

使用文本文件进行内存初始化工作
(1)在程序所在目录下创建两个文本文件page.txt和task.txt
(2)读取文件内容,用循环将文件内容赋值给页表结构体的成员(pagelist)和存放操作数等结构体的成员(worklist)
work_FIFO()

使用双重循环
(1)逻辑地址进行计算页号和页内地址
(2)进行条件判断,如果页号标志位1,即在主存中,进行物理地址转换,否则进行缺页中断处理,使用P[M]数组模拟三个分配的物理块,po始终指向最先进去的页号

六、源代码,要求格式规范,适当加注释,以有助于说明问题为宜,注释不少于三分之一。
#include
#include
#define SizeOfPage 7
#define SizeOfBlock 128
#define M 3
struct info //页表信息结构体
{
int pageno;
int flag; //页标志,1表示该页已在主存,0表示该页不在主存
int block; //块号
char disk[10]; //在磁盘上的位置
int dirty; //更新标志(修改标志)

}pagelist[SizeOfPage];

struct work{
char operands[10];
long adress;
int pagenum; //页号
int page_local;//页内地址
int sign; //标志
int Block;
int page_adress;//物理地址
int page_out; //淘汰页号
int page_back;

}worklist[12];

long po=0; //队列标记
long P[M]={0,1,2}; //假设内存中最多允许M=3个页面

void init_ex1() //内存空间初始化。
{
//memset(pagelist,0,sizeof(pagelist)); 内存空间初始化,第一个值为指定的内存地址,块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作, 其返回值为s。

FILE *fp = fopen("page.txt","r"), *fq = fopen("task.txt","r");
int i = 0;
int a = 0, b = 0, c=0, d=0;
char e[10];
while(fscanf(fp,"%d%d%d%d%s",&a,&b,&c,&d,&e)!=EOF)
{
	pagelist[i].pageno=a;
	pagelist[i].flag=b;
	pagelist[i].block=c;
	pagelist[i].dirty=d;
	strcpy(pagelist[i].disk, e);
	i++;
}
char s[10];
long n = 0;
int k=0;
while(fscanf(fq,"%s%ld",&s,&n)!=EOF)
{
	if(k >= 12)
		break;
	strcpy(worklist[k].operands, s);
	worklist[k].adress=n;
	k++;
}

fclose(fp);
fclose(fq);

}

void print()
{
/* char operands[10];
long adress;
int pagenum; //页号
int page_local;//页内地址
int sign; //标志
int Block;
int page_adress;//物理地址
int page_out; //淘汰页号
int page_back; //是否写回
*/
printf(“以下数据1表示是,0表示否\n”);
printf(“操作数\t逻辑地址\t页号\t页内地址\t是否命中\t物理块号\t物理地址\t淘汰页号\t是否写回\n”);
for(int i=0;i<12;i++)
{
printf("%s\t%ld\t\t%d\t%d\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d",worklist[i].operands,worklist[i].adress,worklist[i].pagenum,worklist[i].page_local,worklist[i].sign,worklist[i].Block,worklist[i].page_adress,worklist[i].page_out,worklist[i].page_back);
printf("\n");
}
}
void work_FIFO()
{

int i,j;
for(i=0;i<12;i++)
{
	worklist[i].pagenum=worklist[i].adress / 128;
	worklist[i].page_local=worklist[i].adress % 128;
	worklist[i].page_back = 0;
    
	for(j=0;j<7;j++)
	{
		if(pagelist[j].pageno == worklist[i].pagenum)
		{
			if(pagelist[j].flag==1)
			{
				worklist[i].Block = pagelist[pagelist[j].pageno].block;
				worklist[i].sign=1;
				//printf("物理块:%d\n",worklist[i].Block);
				worklist[i].page_adress=(pagelist[pagelist[j].pageno].block* SizeOfBlock + worklist[i].page_local);//worklist[i].Block
			//	printf("物理地址:%d\n",worklist[i].page_adress);
				worklist[i].page_out=-1;
				if(!(strcmp(worklist[i].operands,"存")))
				{
					pagelist[worklist[i].pagenum].dirty = 1;		//是否写回磁盘,修改页表
					worklist[i].page_back = 1;
				}

				
			}
			else
			{
				//printf("*%d\n",worklist[i].pagenum);
				pagelist[P[po]].flag=0;   //将flag标志位置0,表示当前页面已被置换出去
				worklist[i].page_out=P[po];
				worklist[i].Block=pagelist[P[po]].block;
				pagelist[j].block=pagelist[P[po]].block;
				worklist[i].page_adress=(worklist[i].Block*SizeOfBlock+worklist[i].page_local);
		   	  
			   pagelist[j].flag=1;
			   worklist[i].sign=0;
			   P[po]=pagelist[j].pageno;   //保存当前页面所在的位置
			   po=(po+1)%M; 

			   if(!(strcmp(worklist[i].operands,"存")))
				{
					pagelist[worklist[i].pagenum].dirty = 1;		//是否写回磁盘,修改页表
					worklist[i].page_back = 1;
				}

			}
		}
		else
		{
			continue;
		}
	}

}

}

int main()
{
init_ex1();
work_FIFO();
print();

return 0;

}
七、运行的结果,要求有对结果的分析C语言模拟实现虚拟存储管理(请求分页存储管理)_第3张图片
结果分析:
页号=int(逻辑地址/每块长度(128)) 页内地址=逻辑地址%每块长度(128)
初始内存时,存在主存的页号有0,1,2号页。下面进行三个举例验证输出结果是否正确:
①第一个操作数为“+”,逻辑地址为:389,页号=int(389/128)=3,页内地址=389%128=5
此时,3号页不在主存中,未命中(为0),产生缺页中断,使用FIFO算法进行页面调度,淘汰最先进入主存的页号,即0页,故0号页淘汰,将淘汰页的物理块赋值给调入页号的物理块,极为5,物理地址为:5128+5=645,操作数不为“存”,不写回外存。
②第二个操作数为“+”,逻辑地址为:150,页号=int(150/128)=1,页内地址=150%128=22
此时,在主存是页号有3,1,2,故命中(为1),物理块号为8,物理地址为:8
128+22=1046,命中,无淘汰页号,即记为-1,操作数不为“存”,不写回外存。
③第四个操作数为“存”,逻辑地址为:78,页号=int(78/128)=0,页内地址=78%128=78
此时,在主存中的页号有1,2,3,未命中,产生缺页中断,根据FIFO算法,淘汰1号页,调入0号页,物理块号为8,物理地址为:8*128+78=1102,操作数为“存”,写回外存,记为1。以此类推,现不再重复验证。
八、主要参考资料
[1] 汤子瀛等. 计算机操作系统(第三版). 西安:西安电子科技大学出版社2007
[2] [美]William Stallings. 操作系统――内核与设计原理. 北京:电子工业出版社 2001
[3] [美]Abraham Silberschatz等. 操作系统概念(第六版) 北京:高等教育出版社 2004
[4] [荷]Andrews Tanenbaum. 现代操作系统(第2版)北京:机械工业出版社 2005
[5] 谭浩强. C程序设计(第四版). 北京:清华大学出版社2010

你可能感兴趣的:(C语言,编程语言,算法,操作系统)