Operating system requests paging storage management experiment code (C language version)

1. Experiment description

This experiment is to simulate the page replacement algorithm in the request paging technology in the virtual storage management mode. If the currently accessed page number has a corresponding memory physical block number, it can be directly accessed (the page number in the physical block can be adjusted if necessary). Otherwise, output the missing page access flag + first, and then judge whether the physical block is full. If it is not full, it will directly swap into the current page. If it is full, first eliminate and swap out the first page number of the physical block in the memory, and then Swap in the current page. FIFO selects the page that has the longest resident time in memory for replacement, and LFU selects the page that has not been referenced for the longest time for replacement.

2. Experimental results

 

3. Experiment code

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>

//作业结构体
typedef struct Job {
	char name[20];		//作业名
	int pageLen;		//页面长度
	int* pageSeq;		//页面顺序
}Job;

//页面结构体
typedef struct Page {
	int n;		//页面序号
	int count;	//计时器
	Page* next;
}Page;

//页面链表
typedef struct List {
	Page* tail;
	Page* head;
	int len;			//记录当前节点个数
	bool haveNewPage;	//记录当前是否有新的页面加入
	int newPageNum;		//记录新页面的序号
}List;

//调度结果保存在一张二维数组中
typedef struct Map {
	int** arr;				//调度结果图,使用动态的二维数组
//更新: 将result.arr由char**改为char*,不将结果转为字符串,而是作为整形数组输出,要添加判断来输出空格和加号
	int len;				//已保存的链表状态个数
	int interruptNum;	//记录中断次数
}Map;

List pageList;		//作业页面队列
int blockNum;		//物理块数
Job job;			//作业
Map result;			//记录调度结果

//初始化
void init() {
	printf("请输入物理块数:");
	scanf("%d", &blockNum);
	pageList.len = 0;
	pageList.head = pageList.tail = (Page*)malloc(sizeof(Page));	//先分配一个头结点
	pageList.head->next = NULL;
}

//页面插入链表
void entryList(int x)
{
	Page* p = (Page*)malloc(sizeof(Page));
	p->n = x;
	p->count = 0;			//初始化p
	p->next = NULL;
	pageList.tail->next = p;
	pageList.tail = p;		//尾插法
	pageList.len++;
}

//页面从表头退出
void outList()
{
	Page* tmp = pageList.head->next;
	pageList.head->next = tmp->next;
	pageList.len--;
	free(tmp);
}

//设置计时器
void setCount()
{
	Page* p = pageList.head->next;
	while (p != NULL)
	{
		p->count++;
		p = p->next;
	}
}

//输入作业
void inputJob() {
	printf("请输入作业名:");
	scanf("%s", job.name);
	printf("请输入作业页面长度:");
	scanf("%d", &job.pageLen);
	job.pageSeq = (int*)malloc(sizeof(int) * job.pageLen);	//根据页面长度动态分配数组记录页面序号
	result.arr = (int**)malloc(sizeof(int*) * job.pageLen);	//先分配二级指针的空间,用于后续保存每次循环链表的状态
	result.len = 0;
	result.interruptNum = 0;								//记录中断次数
	printf("请输入作业页面顺序:\n");
	for (int i = 0; i < job.pageLen; i++)
		scanf("%d", &job.pageSeq[i]);
}

//查找页面是否在链表中
bool isExist(int x) {
	Page* p = pageList.head->next;
	while (p != NULL)
	{
		if (x == p->n)
			return true;
		p = p->next;
	}
	return false;
}

//更新结果
void updateResult()
{
	bool isFull = (pageList.len == blockNum);			//判断页面链表是否已满
	int* p = (int*)malloc(sizeof(int)*(blockNum + 2));			//分配用于记录当前链表状态的空间,3是保存+号和新页面的序号
	Page* q = pageList.head->next;
	if (isFull == false)							//没满,需要填充空格
	{
		for (int i = pageList.len; i < blockNum; i++)
			p[i] = -1;	//代表空格
	}
	for (int i = pageList.len - 1; i >= 0; i--)			//倒序存储链表的页面序号便于输出
	{
		p[i] = q->n;
		q = q->next;
	}
	if (pageList.haveNewPage == true)				//有新页面,更新+
		p[blockNum] = -2;	//代表+号
	else
		p[blockNum] = -1;
	p[blockNum + 1] = pageList.newPageNum;	//新页面序号
	result.arr[result.len] = p;
	result.len++;
}

//打印结果
void printResult(int x)
{
	if (x == 1)
		printf("**********打印作业FIFO调度进入主存页的过程**********\n");
	else
		printf("**********打印作业LRU调度进入主存页的过程**********\n");
	double interruptRate = 0;
	printf("作业名:%s\n", job.name);
	printf("作业调度过程:\n");
	//打印下标
	printf("   ");
	for (int i = 0; i < job.pageLen; i++)
		printf(" %3d", i);
	printf("\n   ");
	//打印页面顺序
	for (int i = 0; i < job.pageLen; i++)
		printf(" %3d", job.pageSeq[i]);
	//打印调度算法情况
	for (int i = 0; i < blockNum+2; i++)	//2是用于打印+号和新页面号的两行
	{
		if (i < blockNum)
			printf("\n%-2d  ", i);			//行号
		else
			printf("\n    ");				//最后两行不打印行号
		for (int j = 0; j < job.pageLen; j++)
		{
			if (result.arr[j][i] == -1)		//先判断是字符还是序号
				printf("%3c ", ' ');
			else if(result.arr[j][i] == -2)
				printf("%3c ", '+');
			else
				printf("%3d ", result.arr[j][i]);	//注意是有20行,竖过来就是将每一列作为新的行
		}
	}
	interruptRate = (double)result.interruptNum / job.pageLen * 100;
	printf("\n缺页中断率为:%.2f\n", interruptRate);//打印缺页中断率
}

//FIFO
void FIFO() {

	//更新每次的状态
	for (int i = 0; i < job.pageLen; i++)
	{
		if (isExist(job.pageSeq[i]) == true)  //页面存在则不用额外操作,只需要说明无新页面
			pageList.haveNewPage = false;
		else {
			result.interruptNum++;			  //页面不存在,发生中断
			if (pageList.len == blockNum)	  //链表已满,表头节点退出,否则直接插入新节点即可
				outList();
			entryList(job.pageSeq[i]);
			pageList.haveNewPage = true;
			pageList.newPageNum = job.pageSeq[i];//更新新入队的页面号
		}
		//更新result
		updateResult();
	}
}

//LRU
void LRU() {
	for (int i = 0; i < job.pageLen; i++)
	{
		if (isExist(job.pageSeq[i]) == true)  //页面存在则找到该节点并置于尾部即可
		{
			Page* pre = pageList.head, * p = pageList.head->next;
			while (p != NULL)				//寻找节点
			{
				if (p->n == job.pageSeq[i])
					break;
				pre = p;
				p = p->next;
			}
			if (p->next != NULL)			//如果已在尾部,只需要重置计时器即可
			{
				pre->next = p->next;		//不在尾部,插入链表尾部
				pageList.tail->next = p;	//调整尾指针
				pageList.tail = p;
				p->next = NULL;				//注意要调整next
			}
			p->count = 0;
			pageList.haveNewPage = false;
		}
		else {
			result.interruptNum++;			//页面不存在,中断次数++
			if (pageList.len == blockNum)	//链表已满,同上
				outList();
			entryList(job.pageSeq[i]);
			pageList.haveNewPage = true;
			pageList.newPageNum = job.pageSeq[i];//更新新入队的页面号
		}
		updateResult();							//更新result和计时器
		setCount();
	}
}

//清理页面链表和result,释放申请的空间
void clear()
{
	Page* p = pageList.head->next, * tmp;
	while (p != NULL)			//释放掉链表所有节点
	{
		tmp = p;
		p = p->next;
		free(tmp);
	}
	pageList.len = 0;
	pageList.tail = pageList.head;
	pageList.head->next = NULL;

	for (int i = 0; i < result.len; i++)//数组
		free(result.arr[i]);	//先释放每个二级指针指向的结果
	free(result.arr);			//再释放所有二级指针
	result.arr = NULL;
	result.len = 0;
}

//选择菜单
void choiceMenu() {
	while (true) {
		int cho;
		printf("**********请求分页式存储管理**********\n");
		printf("       *      1.FIFO分配     *\n");
		printf("       *      2.LRU(LFU)分配 *\n");
		printf("       *      0.退出         *\n");
		printf("\t\t请输入选项:");
		scanf("%d", &cho);
		switch (cho) {
		case 0:
			return;
		case 1:
			inputJob();
			FIFO();
			printResult(1);
			clear();
			break;
		case 2:
			inputJob();
			LRU();
			printResult(2);
			clear();
			break;
		}
	}
}

//7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1
int main() {
	init();
	choiceMenu();
	return 0;
}

Guess you like

Origin blog.csdn.net/OrientalGlass/article/details/130806229