#广工操作系统#实验三 请求调页存储管理方式的模拟C语言

1.实验目的

通过对页面、页表、地址转换和页面置换过程的模拟,加深对请求调页系统的原理和实现过程的理解。

2.实验内容

(1)假设每个页面中可存放10条指令,分配给作业的内存块数为4。

(2)用c语言模拟一个作业的执行过程,该作业共有320条指令,即它的地址空间为32页,目前它的所有页都还未调入内存。在模拟过程中,如果所访问的指令已在内存,则显示其物理地址,并转下一条指令。如果所访问的指令还未装入内存,则发生缺页,此时需记录缺页的次数,并将相应页调入内存。如果4个内存块均已装入该作业,则需进行页面置换,最后显示其物理地址,并转下一条指令。在所有320指令执行完毕后,请计算并显示作业运行过程中发生的缺页率。

(3)置换算法:采用先进先出(FIFO)、最近最久未使用(LRU)和最佳置换(OPT)算法置换算法。

(4)通过随机数产生一个指令序列,共320条指令。

1)指令的地址按下述原则生成:

① 50%的指令是顺序执行的;

    ② 25%的指令是均匀分布在前地址部分;

③ 25%的指令是均匀分布在后地址部分;

具体的实施方法是:

① 在[0,319]的指令地址之间随机选取一起点m;

② 顺序执行一条指令,即执行序号为m+1的指令;

③ 在前地址[0,m-1]中随机选取一条指令并执行,该指令的序号为m1;

④ 顺序执行一条指令,其序号为m1+1的指令;

⑤ 在后地址[m1+2,319]中随机选取一条指令并执行,该指令的序号为m2;

⑥ 顺序执行一条指令,其序号为m2+1的指令;

       重复上述步骤①~⑥,直到执行320次指令。

2)将指令序列变换为页地址流

设页面大小为1K, 用户虚存容量为32K。在用户虚存中,按每K存放10条指令排列虚存地址,即320条指令在虚存中的存放方式为:

第0条~第9条指令为第0页(对应虚存地址为[0,9]);

第10条~第19条指令为第1页(对应虚存地址为[10,19]);

……

……

第310条~第319条指令为第31页(对应虚存地址为[310,319])。

按以上方式,用户指令可组成32页。

37ffeefbdd794bae8e02c4f689c81b23.png

上图为在华为云上OPT运行的结果,修改主函数中的注释即可选择不同的置换算法

以下为C语言源代码


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

#define INSTR_NUM 320 // 指令条数
#define MEMORY_BLOCK_NUM 4 // 物理内存被划分的块数
#define INSTR_NUM_PER_PAGE 10 // 每个页面的指令条数

typedef struct Block {
	int page_id;
	int next; // 在最佳替换算法中OPT使用,FIFO和LRU 均用队列来辅助实现
} Block;

int _index = 0;
int instr[INSTR_NUM]; // 随机产生的指令执行序列数组
int lack_num; // 缺页次数,不同算法中将该值重置为0

Block memory_block[MEMORY_BLOCK_NUM]; // 内存物理块

// 返回某范围的随机数
int getRandom(int start, int end) {
	int t = rand() % (end - start + 1) + start;
	int j;
	for (j = 0; j < _index; j++) {
		if (instr[j] == t) {
			break;
		}
	}
	if (_index == j) {
		instr[_index++] = t;
	}
	int k;
	for (k = 0; k < _index; k++) {
		if (instr[k] == t + 1) {
			break;
		}
	}
	if (_index == k && t + 1 < INSTR_NUM) {
		instr[_index++] = t + 1;
	}
	return t;
}

// 初始化,给指令执行数组赋值
void init() {
	// 得到指令执行顺序,存入数组
	int t = getRandom(0, INSTR_NUM - 1);
	while (_index < INSTR_NUM) {
		if (t == 1 && _index == 2) {
			instr[_index++] = t - 1;
		}
		if (t > 1) {
			int forword = getRandom(0, t - 1);
		}
		if (t <= INSTR_NUM - 3) {
			int last = getRandom(t + 2, INSTR_NUM - 1);
		}
	}
	// 内存置空
	for (int i = 0; i < MEMORY_BLOCK_NUM; i++) {
		memory_block[i].page_id = -1;
	}
}

// 当前页面是否已经调入页框
int isExistInMemory(int curr_page) {
	// 不存在内存中,返回-1 ,存在 返回所在物理块位置
	int is_exist = -1;
	for (int i = 0; i < MEMORY_BLOCK_NUM; i++) {
		if (memory_block[i].page_id == curr_page) {
			is_exist = i;
			break;
		}
	}
	return is_exist;
}

// 是否有空闲页框
Block* findEmpty() {
	Block* empty = NULL;
	for (int i = 0; i < MEMORY_BLOCK_NUM; i++) {
		if (memory_block[i].page_id == -1) {
			empty = &memory_block[i];
			break;
		}
	}
	return empty;
}

// 在OPT中使用,找到应该被替换的页框
int findReplace() {
	int pos = 0;
	for (int i = 0; i < MEMORY_BLOCK_NUM; i++) {
		if (memory_block[i].next > memory_block[pos].next)
			pos = i; //找到应予置换页面,返回BLOCK中位置
	}
	return pos;
}



// 返回最佳被置换的页面
void findBeReplaceBlockByOPT(int index_) {
	for (int i = 0; i < MEMORY_BLOCK_NUM; i++) {
		for (int j = index_ + 1; j < 320; j++) {
			if (memory_block[i].page_id != instr[j] / INSTR_NUM_PER_PAGE) {
				memory_block[i].next = 1000;          //最近此块并没有指令要被访问 
			}
			else { //将来不会用,设置为一个很大数
				memory_block[i].next = j;              //最近此块内要被访问的指令
				break;
			}
		}
	}
}

// 显示当前页的物理块(页框)编号,模拟真实物理地址的计算
void show(int curr_page) {
	//	printf("物理地址分别是:\n");
	for (int i = 0; i < MEMORY_BLOCK_NUM; i++) {
		if (memory_block[i].page_id == curr_page) {
			//			printf("第%d页所在物理块编号:%d ", curr_page, i);
			//			printf("物理地址:%d ", i);
			printf("%d ", i);
			break;
		}
	}
}

// 最佳页面替换算法
void OPT() {
	int pc;
	int curr_page;
	int is_exist;
	int position;
	float lack_num = 0; // Declare and initialize `lack_num` here.
	Block* empty;
	printf("OPT:\n\n");
	for (int i = 0; i < INSTR_NUM; i++) {
		pc = instr[i];
		// 指令是否在内存块中,在则打印,不在则调入
		curr_page = pc / INSTR_NUM_PER_PAGE; // 当前指令所在的页面编号
		is_exist = isExistInMemory(curr_page); // 当前页面是否在内存中 -1 表示不存在
		if (is_exist == -1) {
			lack_num++;
			// 内存是否还有剩余空间,有则直接调入,没有则根据OPT算法找到最合适的页面调出
			empty = findEmpty();
			if (empty != NULL) {
				empty->page_id = curr_page;
			}
			else {
				findBeReplaceBlockByOPT(i);
				position = findReplace();
				memory_block[position].page_id = curr_page;
			}
		}
		show(curr_page);
	}
	printf("\n缺页率:%.2f %%\n", lack_num / 320.0 * 100);
}

// 最近最少使用页面替换算法
void LRU() {
	int pc;
	int curr_page;
	int is_exist;
	Block* empty;
	lack_num = 0;
	printf("LRU:\n\n");
	for (int i = 0; i < INSTR_NUM; i++) {
		int tempQueue[INSTR_NUM]; // 使用数组模拟队列
		int queue_front = 0, queue_rear = -1;
		pc = instr[i];
		curr_page = pc / INSTR_NUM_PER_PAGE;
		is_exist = isExistInMemory(curr_page);
		if (is_exist == -1) {
			lack_num++;
			empty = findEmpty();
			if (empty != NULL) {
				empty->page_id = curr_page;
				// 将新页面放入队列末尾
				tempQueue[++queue_rear] = curr_page;
			}
			else {
				int first = tempQueue[queue_front++];
				// 替换内存中的页面
				for (int j = 0; j < MEMORY_BLOCK_NUM; j++) {
					if (memory_block[j].page_id == first) {
						memory_block[j].page_id = curr_page;
						break;
					}
				}
				// 将新页面放入队列末尾
				tempQueue[++queue_rear] = curr_page;
			}
		}
		else {
			// 存在则将页面移动到队列末尾
			for (int j = queue_front; j <= queue_rear; j++) {
				if (tempQueue[j] == curr_page) {
					// 将当前页面移到队列末尾
					for (int k = j; k < queue_rear; k++) {
						tempQueue[k] = tempQueue[k + 1];
					}
					tempQueue[queue_rear] = curr_page;
					break;
				}
			}
		}
		show(curr_page);
	}
	printf("\n缺页率:%.2f %%\n", lack_num / 320.0 * 100);
}
// 先入先出页面替换算法
void FIFO() {
	int pc;
	int curr_page;
	int is_exist;
	Block* empty;
	lack_num = 0;

	printf("FIFO:\n\n");
	printf("Physical Address:\n");

	for (int i = 0; i < INSTR_NUM; i++) {
		pc = instr[i];
		curr_page = pc / INSTR_NUM_PER_PAGE;

		is_exist = isExistInMemory(curr_page);

		if (is_exist == -1) {
			lack_num++;
			empty = findEmpty();

			if (empty != NULL) {
				empty->page_id = curr_page;
			}
			else {
				int first = memory_block[0].page_id;
				for (int j = 0; j < MEMORY_BLOCK_NUM - 1; j++) {
					memory_block[j].page_id = memory_block[j + 1].page_id;
				}
				memory_block[MEMORY_BLOCK_NUM - 1].page_id = curr_page;
			}
		}
		show(curr_page);
	}
	printf("\nPage Fault Rate: %.2f %%\n", lack_num / 320.0 * 100);
}

int main() {
	// 以时间作为随机数种子
	srand((unsigned)time(NULL));
	init();
	printf("\n随机产生的指令执行序号:\n");
	for (int i = 0; i < INSTR_NUM; i++) {
		printf("%d ", instr[i]);
	}
	printf("\n\n");
	// 每次只能使用一种算法
	OPT();
//	FIFO();
//	LRU();
	return 0;
}


 

 

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值