【操作系统课程设计】请求分页存储管理

摘要:

本课程设计对请求分页存储管理中的六种置换算法进行了模拟,按照我们常见的表示方法进行了输出,并分别求得不同算法及不同页面序列之间的性能曲线图。

整个代码仅使用C语言,这对于只掌握了C语言的同学非常友好。另外需要用到的工具包是EasyX,这是一个比较基础的图形化工具,将用它来完成性能曲线图的绘制(和程序的GUI界面),本博客将一并介绍EasyX工具包的安装方法。

一、课程设计任务描述

请求分页存储管理

(1)请根据理论教材所授内容,采用自己熟悉的编程语言模拟实现OPT、FIFO、LRU、LFU、简单的和改进的CLOCK共六种页面置换算法

(2)要求:(a) 各置换算法所请求的页面序列是随机产生的,而不是人为输入,在执行时应只需改变页面序列的大小就可以得到不同的页面序列,其中随机性通过一定的参数进行控制而且这些参数要便于调整。(b) 对每一算法,程序依次测试物理块数(内存容量)为2、3、4、5、6、7、8七种情况下的缺页率和置换率,并能自动统计分析出各算法缺页率与物理块、随机性之间的关系(要求程序最终能生成性能曲线图)。(c)  程序应能动态显示各算法的具体置换过程

二、需求分析

1、首先,我们需要充分了解六种页面置换算法的具体过程。这部分在教材中已经详细介绍过了,请大家参见《计算机操作系统》教材。

大家对于上图一定非常熟悉,我们将做到输出上图的效果。

我的想法是:为了模拟输出上图,采用一个一维数组numbers[ ]来存放页面序列,一个二维数组stack[ ]来存放每次调用置换算法后,各内存块中的存储情况。

(这里的想法参考了这篇博客

2、其次,自动生成性能曲线图,无非就是生成一张图表,其横轴为内存块数量,纵轴为缺页率,不同算法用不同颜色的曲线描绘。大致如下图所示:

我的想法是,利用EasyX库实现作图(然而后来直接一口气做出了图形化操作界面hhh)

下面介绍EasyX的安装:

第一步:下载EasyX包        https://easyx.cn/

第二步:打开,点下一步,选择你想安装到的开发平台(请同时安装文档,这非常有用!

第三步:安装完成

在使用时,引用头文件即可

#include <graphics.h>              // 引用图形库头文件
#include <conio.h>

 三、实现过程

1、每个置换算法写成一个函数。

2、一些数据结构(如页面序列numbers[ ],页面栈stack[ ]等)设置为全局变量。

3、一些变量(如序列长度l,内存块个数nums等)设计成由用户输入。

4、各置换算法原理这里不叙述,请大家翻书或查找专门资料或直接读代码hhh

完成上述几条后,基本的框架也就出来了,下面展示该“框架”的代码:(缩进很奇怪请忽略)

//框架
//@Dwyanelittle64c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#define MAXSIZE 100

int numbers[MAXSIZE];				//存放页面序列的数组
int nums=0;					//内存块的个数
int l=0;					//序列个数
int stack[8][MAXSIZE];				//页面栈数组



void begin();
void randomnum();	//用于产生随机数
void init();		//初始化
void FIFO();		//FIFO算法
void LRU();			//LRU算法
void OPT();			//最优页面置换算法(OPT)
void LFU();			//LFU算法
void SClock();		//
void IClock();		//
void print();		//输出页面栈
int MAX(int w[]);	//返回max元素下标
int MIN(int w[]);	//返回min元素下标


int main() 
{
    begin();
    FIFO();
    LRU();
    OPT();
    LFU();
    SClock();
    IClock();
    return 0;
}


void begin()//开始菜单界面
{
    int i;

    printf("请输入页面序列的数量(1-100):");
    scanf("%d",&l);

    printf("请输入内存块的数量(2-8):");
    scanf("%d",&nums);

    randomnum();//生成随机页面
    

    printf("页面引用串为:\n");
    for(i=0;i<l;i++)
        printf("%d  ",numbers[i]);
    printf("\n");
}

void randomnum()//如果需要使用随机数生成输入串,调用该函数
{
    int i;
    srand(time(0));//设置时间种子
    for(i = 0; i < l; i++) 
        numbers[i] = rand() % 10;//生成区间0`9的随机页面引用串
}

void init()			//用于每次初始化页面栈中内容
{
    int i,j;
    for(i=0;i<nums;i++)
        for(j=0;j<l;j++)
            stack[i][j]=-1;
}

void print()		//输出各个算法的栈的内容
{
    int i,j;
    for(i=0;i<nums;i++)
    {
        for(j=0;j<l;j++)
        {
		//	Sleep(500);
            if(stack[i][j]==-1)
		printf("*  ");
            else
		printf("%d  ",stack[i][j]);
        }
        printf("\n");
    }
}


int MAX(int w[])
{
	int i;
	int max_val=w[0],max_loc=0;
	for(i=0;i<nums;i++)
	{
		if(w[i]>max_val)
		{
		    max_loc=i;
		    max_val=w[i];
		}
	}
//	printf("max_val=%d,max_loc=%d\n",max_val,max_loc);
	return max_loc;
}

int MIN(int w[])
{
	int i;
	int min_val=w[0],min_loc=0;
	for(i=0;i<nums;i++)
	{
		if(w[i]<min_val)
		{
			min_loc=i;
			min_val=w[i];
		}
	}
	return min_loc;
}

void FIFO()
{
	int i,j,n=0,flag;
	init();
	stack[0][0]=numbers[0];
	for(j=1;j<l;j++)
	{
		flag=0;
		for(i=0;i<nums;i++)			//将上一列复制过来
			stack[i][j]=stack[i][j-1];

		for(i=0;i<nums;i++)
		{
			if (stack[i][j]==numbers[j])	
			{
				flag=1;				//找到匹配,置标志位为1
				break;
			}
		}

		if(flag==0)					//未找到匹配
		{
		
			for(i=nums-2;i>=0;i--)
				stack[i+1][j]=stack[i][j];	//将最远的元素弹出
			stack[0][j]=numbers[j];			//新元素进入
			n++;							//计数器+1
		}
	}
	printf("\n");
        printf("FIFO算法:\n");
	print();
        printf("缺页错误数目为:%d\n",n);
	printf("缺页率为:%.2f\n",float(n)/l);
}




void LRU()
{

	int i,j,n=0,flag,i_loc,i_val;
	init();
	stack[0][0]=numbers[0];
	for(j=1;j<l;j++)
	{
		flag=0;
		for(i=0;i<nums;i++)			//将上一列复制过来
			stack[i][j]=stack[i][j-1];

		for(i=0;i<nums;i++)
		{
			if (stack[i][j]==numbers[j])	
			{
				flag=1;				//命中,置标志位为1
				i_loc=i;			//记录i的位置
				i_val=stack[i][j];	//记录i的值
				break;
			}
		}


		if(flag==0)							//未命中
		{
		
			for(i=nums-2;i>=0;i--)
				stack[i+1][j]=stack[i][j];	//将最远的元素弹出
			stack[0][j]=numbers[j];			//新元素进入
			n++;							//计数器+1
		}
		if(flag==1)							//命中
		{
			for(i=i_loc-1;i>=0;i--)			//令命中元素置顶
			{
				stack[i+1][j]=stack[i][j];	//error
			}
			stack[0][j]=i_val;
		}


	}
	printf("\n");
    printf("LRU算法:\n");
	print();
    printf("缺页错误数目为:%d\n",n);
	printf("缺页率为:%.2f\n",float(n)/l);	

}


void OPT()
{

	int i,j,k,n=0;					//k表示寻找w数组时的j
	int flag=0,i_loc,flag_0,flag_i;	//flag表示是否命中,flag_0表示是否有空内存块,flag_i表示空内存块位置
	int w[8];						//权重数组
	for(i=0;i<8;i++)
		w[i]=MAXSIZE;
	init();
	stack[0][0]=numbers[0];
	for(j=1;j<l;j++)
	{
		flag=0;
		for(i=0;i<nums;i++)
			stack[i][j]=stack[i][j-1];
		for(i=0;i<nums;i++)
			if (stack[i][j]==numbers[j])	//判断是否命中
			{
				flag=1;
				break;
			}
		flag_0=0;							//flag_0置零
		for(i=0;i<nums;i++)
			if(stack[i][j]==-1)				//判断是否有空块
			{
				flag_0=1;
				flag_i=i;
				break;
			}
		if(flag!=1)					//未命中
		{
			if(flag_0==1)				//有空页
				stack[flag_i][j]=numbers[j];
			else
			{

				for(i=0;i<nums;i++)
				{
						for(k=j;k<l;k++)
						{
							if(stack[i][j]==numbers[k])
							{
								w[i]=k;
								break;
							}
						}
				}
				i_loc=MAX(w);		//max函数返回数组w中最大元素的下标
				stack[i_loc][j]=numbers[j];
			
			}
			n++;				//计数器++
		}
	}
	printf("\n");
    printf("OPT算法:\n");
	print();
    printf("缺页错误数目为:%d\n",n);
	printf("缺页率为:%.2f\n",float(n)/l);	
}


void LFU()
{
	int i,j,n=0;					//k表示寻找w数组时的j
	int flag=0,i_loc,flag_0,flag_i;	//flag表示是否命中,flag_0表示是否有空内存块,flag_i表示空内存块位置
	int w[8]={0};					//访问计数器
	init();
	stack[0][0]=numbers[0];
	for(j=1;j<l;j++)
	{
		flag=0;
		for(i=0;i<nums;i++)
			stack[i][j]=stack[i][j-1];
		for(i=0;i<nums;i++)
			if (stack[i][j]==numbers[j])//判断是否命中
			{
				flag=1;
				w[i]++;
				break;
			}
		flag_0=0;					//flag_0置零
		for(i=0;i<nums;i++)
			if(stack[i][j]==-1)		//判断是否有空块
			{
				flag_0=1;
				flag_i=i;
				break;
			}
		if(flag!=1)					//未命中
		{
			if(flag_0==1)				//有空页
				stack[flag_i][j]=numbers[j];
			else
			{
				i_loc=MIN(w);	//max函数返回数组w中最大元素的下标
				stack[i_loc][j]=numbers[j];
				w[i_loc]=0;
			}
			n++;				//计数器++
		}
	}
	printf("\n");
    printf("LFU算法:\n");
	print();
    printf("缺页错误数目为:%d\n",n);
	printf("缺页率为:%.2f\n",float(n)/l);	
}




void SClock()
{
	int i,j,n=0;				//k表示寻找w数组时的j
	int flag=0,flag_0,flag_i;	//flag表示是否命中,flag_0表示是否有空内存块,flag_i表示空内存块位置
	int a[8]={0};				//访问位数组
	int ii=0;					//代替指针
	init();
	stack[0][0]=numbers[0];
	for(j=1;j<l;j++)
	{
		flag=0;
		for(i=0;i<nums;i++)			//将上一列的复制过来
			stack[i][j]=stack[i][j-1];
		for(i=0;i<nums;i++)
		{
			
			if (stack[i][j]==numbers[j])//判断是否命中
			{
				flag=1;
				a[i]=1;
				ii=(ii+1)%nums;
				break;
			}
			else
			{
				a[i]=0;
				ii=(ii+1)%nums;
			}

			
		}
		flag_0=0;					//flag_0置零
		for(i=0;i<nums;i++)
			if(stack[i][j]==-1)		//判断是否有空块
			{
				flag_0=1;
				flag_i=i;
				break;
			}
		if(flag!=1)					//未命中
		{
			if(flag_0==1)				//有空页
			{
				stack[flag_i][j]=numbers[j];//插入数据
				a[flag_i]=1;				//访问位 置1
				ii=(ii+1)%nums;				//循环+1
			}
			else
			{
				stack[ii][j]=numbers[j];
				a[i]=1;
				ii=(ii+1)%nums;
			}
			n++;				//计数器++
		}
	}
	printf("\n");
    printf("SClock算法:\n");
	print();
    printf("缺页错误数目为:%d\n",n);
	printf("缺页率为:%.2f\n",float(n)/l);
}


void IClock()
{
	int i,j,n=0;					
	int flag=0,flag_0,flag_i;	//flag表示是否命中,flag_0表示是否有空内存块,flag_i表示空内存块位置
	int t1=0,t2=0,t3=0;			//扫描轮次
	int a[8]={0};				//访问位数组
	int m[8]={0};				//修改位数组
	int ii=0;					//代替指针
	init();
	stack[0][0]=numbers[0];

	for(j=1;j<l;j++)
	{
		flag=0;
		for(i=0;i<nums;i++)		//将上一列的复制过来
			stack[i][j]=stack[i][j-1];
		for(i=0;i<nums;i++)
		{
			
			if (stack[i][j]==numbers[j])//判断是否命中
			{
				flag=1;
				a[i]=1;
				ii=(ii+1)%nums;
				break;
			}
			else
			{
				a[i]=0;
				ii=(ii+1)%nums;
			}	
		}
		flag_0=0;					//flag_0置零
		for(i=0;i<nums;i++)
			if(stack[i][j]==-1)		//判断是否有空块
			{
				flag_0=1;
				flag_i=i;
				break;
			}
		if(flag!=1)					//未命中
		{
			if(flag_0==1)				//有空页
			{
				stack[flag_i][j]=numbers[j];//插入数据
				a[flag_i]=1;				//访问位 置1
				ii=(ii+1)%nums;				//循环+1
			}
			else							//未命中(教材p167)
			{
				for(i=0;i<nums;i++)			//第一次扫描
					if(a[i]==0 && m[i]==0)
					{
						stack[i][j]=numbers[j];
						t1=1;
						break;
					}
				if(t1==0)
					for(i=0;i<nums;i++)		//第二次扫描
					{
						a[i]=1;				//A置1
						if(a[i]==0 && m[i]==1)
						{
							stack[i][j]=numbers[j];
							t2=1;
							break;
						}
					}
				if(t2==0)				//第三次扫描
				{
					for(i=0;i<nums;i++)
						a[i]=0;				//整体A置0
					for(i=0;i<nums;i++)
						if(a[i]==0 && m[i]==0)
						{
							stack[i][j]=numbers[j];
							t3=1;
							break;
						}
				}
				if(t3==0)					//第三次后半截扫描
				{
					for(i=0;i<nums;i++)
					{
						if(a[i]==0 && m[i]==1)
						{
							stack[i][j]=numbers[j];
							t2=1;
							break;
						}
					}
				}
			}
			n++;				//计数器++
		}
	}
	printf("\n");
    printf("IClock算法:\n");
	print();
    printf("缺页错误数目为:%d\n",n);
	printf("缺页率为:%.2f\n",float(n)/l);
}

 运行结果如图:

做到这儿,课程设计及格应该是没问题了。但我们还有两个任务没有完成:

实现 随机性的控制  和  自动生成性能曲线图

1、首先做简单一点的前者,我的理解是,假设随机性用参数x控制。x越小,则生成的页面序列前后之间相关性越小,即越随机;x越大,则生成的页面序列前后之间相关性越大,即越不随机。这样理解后,代码实现就很简单了,只需稍作修改:

void randomnum(int x)//如果需要使用随机数生成输入串,调用该函数,x表示随机性参数
{
	int i, k, n;
	srand(time(0));//设置时间种子
	for (i = 0; i < l; i++)
	{
		numbers[i] = rand() % 10;		//生成区间0`9的随机页面引用串
		if (i > 0 && numbers[i] != numbers[i - 1])
		{
			for (k = 0;k < x;k++)		//控制随机值的随机性
			{                                
				numbers[i] = rand()%10;
				if (numbers[i] == numbers[i - 1])
					break;
			}
		}
	}
}

2、然后是生成性能曲线图。关于该图表的描述前面已经介绍过了。

我的想法是:先将原始数据存放起来(如使用二维数组存放:某个页面序列下,不同算法之间的缺页率; 或是在某个算法中,不同内存块数之间的缺页率等),然后利用easyx包中提供的函数,将对应的数据画成图的形式即可。

(本人参考这篇博客入门easyx的)

比如说:用啥啥啥函数创建一个窗口,用line()函数绘制一条线段,用outtextxy()函数在指定位置输出字符串噔噔蹬蹬。

                                            详情请参见easyx文档说明!(请一定去看!)

 本人做出来的 性能曲线图 大概长这样:

 (可见,当页面序列足够长(1000)时,OPT作为一种理论上的算法,确实厉害嗷)

3、最后。如果按照课程设计的要求,做完上述“框架”的内容 并且生成一幅类似上图的曲线图,课设已经完成任务了。但我出于对初识easyx的新鲜感,为整个程序做了一个图形化界面。(花了许多不必要的时间)

展示部分截图:

 

 

 

到这里,我的课程设计就全部完成了

四、结语

 由于本人敲代码能力确实有限,加之时间紧促,没有进行优化。整个包含图形化界面的代码有将近2k行,这里就不展示了。如有需要(?)可联系up邮箱:1660584637@qq.com

这是本人第一次发布博客,若其中有错误之处恳请各位批评指正,有疑问的地方也欢迎一起讨论,感谢各位!

通过《操作系统》课程实训,达到以下目的:(1)巩固和加深对操作系统(OS)原理的理解,初步掌握操作系统组成模块和应用接口的使用方法,提高进行工程设计和系统分析的能力;(2)通过相关课题的设计,锻炼学生解决复杂工程问题的能力;(3)通过选做相关的课题,提高学生查阅资料、相互交流沟通的能力,锻炼学生使用信息化工具的能力; 请求页式管理是一种常用的虚拟存储管理技术。本设计通过请求页式存储管理中页面置换算法模拟设计,了解虚拟存储技术的特点,掌握请求页式管理的页面置换算法。 (1)从置换算法中任选 2 种(OPT、 FIFO、LRU、Clock);(2)建立页表;(3) 设计的输入数据要能体现算法的思想(4) 模拟缺页中断过程;(5)求出各置换算法中的缺页次数和置换次数以及依次被换出的页号;(6)利用Java Swing进行图形化界面设计。 在此次实训过程中,我先是完成了FIFO、LRU、OPT、Clock四个算法的实现,之后结合Java的Swing图形化界面,将算法融入到图形化界面中,并且可以进行序列长度和运行时间的初始化,紧接着,可以将序列和物理块进行随机生成序列,最后,在算法执行中,可以将缺页中断过程显示在文本区域内,并且在文本区域内可以显示缺页次数、置换次数、被换页号的实时统计。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值