一、实验目的
二、实验类型
综合性实验。综合高级语言、数据结构、存储管理模型等多方面的知识
三、实验示例
例题
设计一个请求页式存储管理方案。并编写模拟程序实现之。产生一个需要访问的指令地址流。它是一系列需要访问的指令的地址。为不失一般性,你可以适当地(用人工指定地方法或用随机数产生器)生成这个序列,使得
50%的指令是顺序执行的。25%的指令均匀地散布在前地址部分,25%的地址是均匀地散布在后地址部分 为简单起见。页面淘汰算法采用
FIFO页面淘汰算法,并且在淘汰一页时,只将该页在页表中抹去。而不再判断它是否被改写过,也不将它写回到辅存。
具体的做法可以是:
产生一个需要访问的指令地址流;
指令合适的页面尺寸(例如以 1K或2K为1页);
指定内存页表的最大长度,并对页表进行初始化;
每访问一个地址时,首先要计算该地址所在的页的页号,然后查页表,判断该页是否在主存——如果该页已在主存,则打印页表情况;如果该页不在主存且页表未满,则调入一页并打印页表情况;如果该页不足主存且页表已满,则按 FIFO页面淘汰算法淘汰一页后调入所需的页,打印页表情况; 逐个地址访问,直到所有地址访问完毕。
编写并调试完成请求页式存储管理程序。(参考课本P145-149例子)
页面置换算法:最佳置换算法(OPT)、先进先出算法(FIFO)和最近最少用算法(LRU)。
要求打印每个页面置换算法的页面置换变化示意图、缺页中断次数和缺页中断率,以比较各种算法的优缺点。
#include
#include
#include
using namespace std;
//【约定】作业名不能为0,可以取1~9。
int read[50]; //存取文件读取的作业
int page_length; //页内作业数,最大不超过9
double page_fault_interrupt = 0; //记录缺页中断次数
MyLinkedList *the_page = new MyLinkedList();
int total = read_data(0);
//一页,容量为page_content
class MyLinkedList {
public:
struct LinkedNode {
int val;
LinkedNode *next;
LinkedNode(int val) : val(val), next(nullptr) {}
};
private:
LinkedNode *dummy_head;
int size;
public:
MyLinkedList() {
//虚拟头节点
dummy_head = new LinkedNode(0);
size = 0;
}
int get(int index) {
if (index > size - 1)
return -1;
LinkedNode *tmp = dummy_head;
for (int i = 0; i <= index; i++) {
tmp = tmp->next;
}
return tmp->val;
}
void addAtHead(int val) {
auto *head = new LinkedNode(val);
head->next = dummy_head->next;
dummy_head->next = head;
size++;
}
void addAtTail(int val) {
LinkedNode *last = dummy_head;
while (last->next != NULL) {
last = last->next;
}
last->next = new LinkedNode(val);
size++;
}
void addAtIndex(int index, int val) {
LinkedNode *tmp = dummy_head;
for (int i = 0; i < index; i++) {
tmp = tmp->next;
}
auto *addedNode = new LinkedNode(val);
if (tmp != nullptr) {
addedNode->next = tmp->next;
tmp->next = addedNode;
size++;
}
}
void deleteAtIndex(int index) {
LinkedNode *deletedNode = nullptr;
LinkedNode *tmp = dummy_head;
for (int i = 0; i < index; i++) {
tmp = tmp->next;
}
if (tmp != nullptr)
deletedNode = tmp->next;
if (tmp != nullptr && tmp->next != nullptr) {
tmp->next = tmp->next->next;
delete deletedNode;
size--;
}
}
int find(int val) { //找到返回index,没有返回-1
LinkedNode *tmp = dummy_head->next;
for (int i = 0; i < size; i++) {
if (tmp->val == val)
return i;
tmp = tmp->next;
}
return -1;
}
int getSize() const {
return size;
}
void Myprint(int break_or_not, int insert) {
if(break_or_not)
page_fault_interrupt++; //更新缺页中断次数
cout << insert << " -> ";
LinkedNode *t = dummy_head;
int i = page_length + 1;
while (t->next) {
t = t->next;
cout << "|" << t->val;
i--;
}
while (i--) {
cout << "| ";
}
if (break_or_not)
cout << "+";
cout << endl;
}
};
void menu() {
cout << "************************************************************************" << endl;
cout << " 页面置换算法 " << endl;
cout << " 1. OPT 2. FIFO 3. LRU 4. 退出 " << endl;
int choose;
recin:
cin >> choose;
if(choose == 1 || choose == 2 || choose == 3) {
cout << "请输入页内作业数,最大不超过9:";
cin >> page_length;
}
switch (choose) {
case 1:
OPT();
break;
case 2:
FIFO();
break;
case 3:
LRU();
break;
case 4:
cout << "程序正常结束,欢迎再次使用。";
exit(-1);
default:
cout << "输入错误,请重新输入。" << endl;
goto recin;
}
}
void OPT() {
page_fault_interrupt = 0; //初始化缺页中断次数
cout << "OPT算法页面变化示意图:" << endl;
for (int i = 0; i < total; i++) {
if (the_page->getSize() < page_length) { //1. 页未满
//输出此时页内容
the_page->Myprint(1, read[i]);
the_page->addAtTail(read[i]);
} else if (the_page->find(read[i]) != -1) { //2. 页满,该页本来就有这个作业,直接调用即可。
the_page->Myprint(0, read[i]);
} else {
//3. 页满,计算作业调用优先级
auto *tmp = new MyLinkedList;
//此for循环退出条件:a. 遍历完毕 b. tmp满了
for (int j = i + 1; j < total; j++) { //往后找最后(或不会)调用的作业
if (the_page->find(read[j]) != -1) { //该作业需要被调用
if (tmp->find(read[j]) == -1) { //之前没有发现它,直接加在尾部就行
tmp->addAtTail(read[j]);
if (tmp->getSize() == page_length) { //tmp满了,说明作业找齐了,退出循环
break;
}
}
}
}
int mark;
if (tmp->getSize() == page_length) { //1. tmp满了,置换tmp最后一个
mark = the_page->find(tmp->get(page_length - 1));
the_page->deleteAtIndex(mark);
} else { //2. tmp未满,置换不在tmp的即可
for (int j = 0; j < page_length; j++) {
if (tmp->find(the_page->get(j)) == -1) { //tmp的作业找不到就被置换
the_page->deleteAtIndex(j);
mark = j;
break;
}
}
}
the_page->addAtIndex(mark, read[i]);
the_page->Myprint(1, read[i]);
delete (tmp); //回收tmp,以免重复使用,内存冲突
}
}
//清一下页面,方便其他算法共用the_page
delete(the_page);
the_page = new MyLinkedList;
cout << "该算法一共发生了 " << page_fault_interrupt << " 次页面置换,缺页中断率为 "
<< page_fault_interrupt / total * 100 << "%" << endl;
}
void FIFO(){
page_fault_interrupt = 0; //初始化缺页中断次数
cout << "FIFO算法页面变化示意图:" << endl;
for (int i = 0; i < total; i++) {
if (the_page->getSize() < page_length) { //1. 页未满
//输出此时页内容
the_page->addAtTail(read[i]);
the_page->Myprint(1, read[i]);
} else if (the_page->find(read[i]) != -1) { //2. 页满,该页本来就有这个作业,直接调用即可。
the_page->Myprint(0, read[i]);
} else {
//3. 页满,先进先出
the_page->deleteAtIndex(0);
the_page->addAtTail(read[i]);
the_page->Myprint(1, read[i]);
}
}
//清一下页面,方便其他算法共用the_page
delete(the_page);
the_page = new MyLinkedList;
cout << "该算法一共发生了 " << page_fault_interrupt << " 次页面置换,缺页中断率为 "
<< page_fault_interrupt / total * 100 << "%" << endl;
}
void LRU(){
page_fault_interrupt = 0; //初始化缺页中断次数
cout << "LRU算法页面变化示意图:" << endl;
//【约定】尾部是最新的
for (int i = 0; i < total; i++) {
if (the_page->getSize() < page_length) { //1. 页未满
//输出此时页内容
the_page->addAtTail(read[i]);
the_page->Myprint(1, read[i]);
} else if (the_page->find(read[i]) != -1) { //2. 页满,调换一下顺序,将最新的放尾部
the_page->deleteAtIndex(the_page->find(read[i]));
the_page->addAtTail(read[i]);
the_page->Myprint(0, read[i]);
} else {
//3. 页满,将最旧的置换成插入的作业
the_page->deleteAtIndex(0); //头部是最旧的
the_page->addAtTail(read[i]);
the_page->Myprint(1, read[i]);
}
}
//清一下页面,方便其他算法共用the_page
delete(the_page);
the_page = new MyLinkedList;
cout << "该算法一共发生了 " << page_fault_interrupt << " 次页面置换,缺页中断率为 "
<< page_fault_interrupt / total * 100 << "%" << endl;
}
int read_data(int print_or_not) {
ifstream in("C:\\Users\\Louis\\Desktop\\project\\CLion_files\\exp7\\data.txt");
if (!in.is_open()) {
cout << "路径错误或者文件不存在!";
exit(1);
}
char buffer[256]; //读取文件之用
in.getline(buffer, 100);
int j = 0;
if (print_or_not)
cout << "页面序列为:";
int sub = 48; //"0" - 0 = 48
for (int i = 0; buffer[i] != '.'; i += 3, j++) {
read[j] = buffer[i] - sub;
if (print_or_not)
cout << " " << read[j];
}
cout << endl;
return j; //返回作业数目
}
int main() {
read_data(1);
while(true){
menu();
}
}
data.txt
7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1, .
结果: