操作系统实验三虚拟存储管理C++

实验目的

存储管理的主要功能之一是合理地分配空间。请求分页存储管理是常用的虚拟存储管理技术。本实验的目的是请求分页存储管理中页面置换算法模拟设计,了解虚拟存储管理技术的特点,掌握请求分页存储管理的页面置换方法。

实验内容

(1). 通过随机数产生一个指令序列,共 320 条指令。指令的地址按下述原则生成:
① 50 %的指令是顺序执行的;
② 25 %的指令是均匀分布在前地址部分;
③ 25 %的指令是均匀分布在后地址部分。

具体的实施方法是:
④ 在[ 0,319 ]的指令地址之间随机选取一起点 m;
⑤ 顺序执行一条指令,即执行地址为 m + 1 的指令;
⑥ 在前地址[0,m+1]中随机选取一条指令并执行,该指令的地址为m’;
⑦ 顺序执行一条指令,其地址为 m’+1;
⑧ 在后地址[m’+ 2,319]中随机选取一条指令并执行;
⑨ 重复上述步骤,直至执行 320 次指令。

(2). 将指令序列变换成页地址流
设: ① 页面大小为1;② 内存容量为4到32KB;③ 用户虚存容量为 32KB (即32页);
在用户虚存中,按每页存放 10 条指令排列虚存地址,即 320 条指令在虚存中的存放方式为:
第 0 条到第 9 条指令存放在 0 号页(对应的虚存地址为[ 0,9]) ;
第10 条到第 19 条指令存放在1号页(对应的虚存地址为([10,19]) ;

第310条到第319条指令存放在31号页(对应的虚存地址为[310,319]) ;
按以上方式,用户指令可组成 32 页。

实验说明

完成最佳置换算法(OPT)、先进先出置换算法(FIFO)、最近最久未使用置换算法(LRU)三个置换算法即可
LFU及NUR置换算法为可选内容。
命中率:1 -(页面失效次数)/(页地址流长度)在本实验中,页地址流的长度为 320 ,页面失效次数为每次访问相应指令时,该指令所对应的页不在内存的次数。
随机数生成可以使用rand()函数,但在一些编译器上会有警告,推荐使用C++11给的随机函数生成库,感兴趣可以自行查找,本实验无相关说明。

注意:如果遇到在visual stdio编译报错,报错内容是std::至少需要c++17。请查询如何修改编译器C++编译版本

实现步骤

实现中采用了策略者设计模式,如果不清楚也不影响

以下抽象基类及其三个子类都存放在my_algorithm.h头文件

首先实现一个抽象基类
基类中包含一个page_change(…)纯虚函数,要求子类重写

// 页面置换算法 抽象基类
class algorithm {
protected:
    // 记录页面失页次数
    double page_invalid_number = 0;
public:
    algorithm() = default;
    double get_page_invalid_number() const {
        return page_invalid_number;
    }
    // 页面置换 纯虚函数 要求子类重写实现
    virtual void page_change(int frame, vector<int> &page_address) = 0;
    virtual ~algorithm() = default;
};

实现FIFO置换算法
思想:使用List模拟队列,先进先出

// 先进先出置换算法 first-in first-out
class FIFO : public algorithm {
private:
    list<int> page_queue;
public:
    void page_change(int frame, vector<int> &page_address) override {
        page_invalid_number = 0;
        page_queue.clear();

        for (int i = 0; i < 320; ++i) {
            bool flag = false;
            for (const auto &it: page_queue) {
                if (it == page_address[i]) {
                    flag = true;
                    break;
                }
            }
            if (!flag) {
                ++page_invalid_number;
                if (page_queue.size() >= frame) {
                    page_queue.pop_front();
                }
                page_queue.push_back(page_address[i]);
            }
        }
    }
};

实现LRU置换算法
思想:使用List模拟栈,栈底始终是最早访问到的页面,栈顶是最新访问到的页面,每次置换栈底的页面

// 最近最久未使用置换算法 least recently used
class LRU : public algorithm {
private:
    list<int> page_stack;
public:
    void page_change(int frame, vector<int> &page_address) override {
        page_invalid_number = 0;
        page_stack.clear();

        for (int i = 0; i < 320; ++i) {
            bool flag = false;
            for (auto it = page_stack.begin(); it != page_stack.end(); ++it) {
                if (*it == page_address[i]) {
                    flag = true;
                    page_stack.erase(it);
                    page_stack.push_back(page_address[i]);
                    break;
                }
            }

            if (!flag) {
                ++page_invalid_number;
                if (page_stack.size() >= frame) {
                    page_stack.pop_front();
                }
                page_stack.push_back(page_address[i]);
            }
        }
    }
};

实现OPT置换算法
思想:选择未来不会使用到或者最久不会使用到的页面进行置换

// 最佳置换算法 optimal
class OPT : public algorithm {
private:
    vector<int> page_queue;
    unordered_map<int, int> next_occurrence; // 存储每个页面下一次出现的位置
public:
    void page_change(int frame, vector<int> &page_address) override {
        page_invalid_number = 0;
        page_queue.clear();
        next_occurrence.clear();

        for (int i = 0; i < page_address.size(); ++i) {
            if (next_occurrence.find(page_address[i]) == next_occurrence.end()) {
                next_occurrence[page_address[i]] = INT_MAX; // 未知下一次出现位置的页面设为最大值
            }

            // 更新每个页面下一次出现的位置
            for (int j = i + 1; j < page_address.size(); ++j) {
                if (page_address[j] == page_address[i]) {
                    next_occurrence[page_address[i]] = j;
                    break;
                }
            }

            // 页面失效
            if (find(page_queue.begin(), page_queue.end(), page_address[i]) == page_queue.end()) {
                ++page_invalid_number;
                if (page_queue.size() >= frame) {
                    int replace_page = page_queue[0];
                    int max_next_occurrence = next_occurrence[page_queue[0]];
                    // 选择下一个要替换的页面
                    for (int j = 1; j < page_queue.size(); ++j) {
                        if (next_occurrence[page_queue[j]] > max_next_occurrence) {
                            replace_page = page_queue[j];
                            max_next_occurrence = next_occurrence[page_queue[j]];
                        }
                    }

                    // 替换页面
                    page_queue.erase(remove(page_queue.begin(), page_queue.end(), replace_page),
                                     page_queue.end());
                }
                page_queue.push_back(page_address[i]); // 将新的页面加入队列
            }
        }
    }
};

实现VSM类,虚拟存储管理 (Virtual Storage Management)

VSM类包含以下两个私有属性
command使用集合保存,是因为老师要求320条指令不能重复

private:
    // 存放指令
    unordered_set<int> command;
    // 存放页地址流
    vector<int> page_address;

VSM类下包含两个公共方法
其中Random(…)函数是自定义的保护方法,下面有给出

public:
	// 通过随机数生成指令
    inline void create_command() {
        srand(time(nullptr));
        int m2;
        int m = Random(0, 318);

        while (command.size() < 320) {
            command.insert(m);
            command.insert(m + 1);
            m2 = m + 1;
            m = Random(0, m2 - 1); // 在[0, m2-1]的随机数
            command.insert(m);
            command.insert(m + 1);
            m = Random(m + 2, 318); // 生成范围在[m2+1, 318]的随机数
        }
    }

    // 将指令序列变为页地址流
    inline void ToPage_address() {
        page_address.resize(command.size());
        int i = 0;
        auto it = command.begin();
        while (i < 320 && it != command.end()) {
            page_address[i++] = *it / 10;
            ++it;
            if (it == command.end()) {
                it = command.begin(); // 重新从头开始循环
            }
        }
    }

protected:
    static int Random(int begin, int end) {
        return rand() % (end - begin + 1) + begin;
    }

完整代码

请注意文件模块的划分

//请新建一个名为my_algorithm.h的头文件保存下面内容
#ifndef OS_03_MY_ALGORITHM_H
#define OS_03_MY_ALGORITHM_H

#include <vector>
#include <random>
#include <unordered_map>
#include <queue>
#include <list>
#include <stack>
#include <algorithm>

using namespace std;

// 页面置换算法 抽象基类
class algorithm {
protected:
    // 记录页面失页次数
    double page_invalid_number = 0;
public:
    algorithm() = default;
    [[nodiscard]] double get_page_invalid_number() const {
        return page_invalid_number;
    }
    // 页面置换 纯虚函数 要求子类重写实现
    virtual void page_change(int frame, vector<int> &page_address) = 0;
    virtual ~algorithm() = default;
};

// 先进先出置换算法 first-in first-out
class FIFO : public algorithm {
private:
    list<int> page_queue;
public:
    void page_change(int frame, vector<int> &page_address) override {
        page_invalid_number = 0;
        page_queue.clear();
        for (int i = 0; i < 320; ++i) {
            bool flag = false;
            for (const auto &it: page_queue) {
                if (it == page_address[i]) {
                    flag = true;
                    break;
                }
            }
            if (!flag) {
                ++page_invalid_number;
                if (page_queue.size() >= frame) {
                    page_queue.pop_front();
                }
                page_queue.push_back(page_address[i]);
            }
        }
    }
};

// 最近最久未使用置换算法 least recently used
class LRU : public algorithm {
private:
    list<int> page_stack;
public:
    void page_change(int frame, vector<int> &page_address) override {
        page_invalid_number = 0;
        page_stack.clear();
        for (int i = 0; i < 320; ++i) {
            bool flag = false;
            for (auto it = page_stack.begin(); it != page_stack.end(); ++it) {
                if (*it == page_address[i]) {
                    flag = true;
                    page_stack.erase(it);
                    page_stack.push_back(page_address[i]);
                    break;
                }
            }

            if (!flag) {
                ++page_invalid_number;
                if (page_stack.size() >= frame) {
                    page_stack.pop_front();
                }
                page_stack.push_back(page_address[i]);
            }
        }
    }
};

// 最佳置换算法 optimal
class OPT : public algorithm {
private:
    vector<int> page_queue;
    unordered_map<int, int> next_occurrence; // 存储每个页面下一次出现的位置
public:
    void page_change(int frame, vector<int> &page_address) override {
        page_invalid_number = 0;
        page_queue.clear();
        next_occurrence.clear();
        for (int i = 0; i < page_address.size(); ++i) {
            if (next_occurrence.find(page_address[i]) == next_occurrence.end()) {
                next_occurrence[page_address[i]] = INT_MAX; // 未知下一次出现位置的页面设为最大值
            }
            // 更新每个页面下一次出现的位置
            for (int j = i + 1; j < page_address.size(); ++j) {
                if (page_address[j] == page_address[i]) {
                    next_occurrence[page_address[i]] = j;
                    break;
                }
            }
            // 页面失效
            if (find(page_queue.begin(), page_queue.end(), page_address[i]) == page_queue.end()) {
                ++page_invalid_number;
                if (page_queue.size() >= frame) {
                    int replace_page = page_queue[0];
                    int max_next_occurrence = next_occurrence[page_queue[0]];
                    // 选择下一个要替换的页面
                    for (int j = 1; j < page_queue.size(); ++j) {
                        if (next_occurrence[page_queue[j]] > max_next_occurrence) {
                            replace_page = page_queue[j];
                            max_next_occurrence = next_occurrence[page_queue[j]];
                        }
                    }
                    // 替换页面
                    page_queue.erase(remove(page_queue.begin(), page_queue.end(), replace_page),
                                     page_queue.end());
                }
                page_queue.push_back(page_address[i]); // 将新的页面加入队列
            }
        }
    }
};
#endif //OS_03_MY_ALGORITHM_H

//请新建一个名为The_Client.h的头文件保存下面内容
#ifndef OS_03_THE_CLIENT_H
#define OS_03_THE_CLIENT_H

#include <unordered_set>
#include "my_algorithm.h"

//虚拟存储管理 (Virtual Storage Management)
class VSM {
private:
    // 存放指令
    unordered_set<int> command;
    // 存放页地址流
    vector<int> page_address;
    // 算法指针
    algorithm *algoPtrO, *algoPtrF, *algoPtrL;
protected:
    static int Random(int begin, int end) {
        return rand() % (end - begin + 1) + begin;
    }
public:
    //Client() = default;   不用默认构造函数 因为要传入算法指针
    ~VSM() = default;
    explicit VSM(algorithm *algorithm_ptrO, algorithm *algorithm_ptrF, algorithm *algorithm_ptrL) {
        this->algoPtrO = algorithm_ptrO;
        this->algoPtrF = algorithm_ptrF;
        this->algoPtrL = algorithm_ptrL;
    }
    // 通过随机数生成指令
    inline void create_command() {
        srand(time(nullptr));
        int m2;
        int m = Random(0, 318);
        while (command.size() < 320) {
            command.insert(m);
            command.insert(m + 1);
            m2 = m + 1;
            m = Random(0, m2 - 1); // 在[0, m2-1]的随机数
            command.insert(m);
            command.insert(m + 1);
            m = Random(m + 2, 318); // 生成范围在[m2+1, 318]的随机数
        }
    }
    // 将指令序列变为页地址流
    inline void ToPage_address() {
        page_address.resize(command.size());
        int i = 0;
        auto it = command.begin();
        while (i < 320 && it != command.end()) {
            page_address[i++] = *it / 10;
            ++it;
            if (it == command.end()) {
                it = command.begin(); // 重新从头开始循环
            }
        }
    }
    inline void Run() {
        // 物理块从4到32
        printf("page frames\t\tFIFO\t\t\tLRU\t\t\tOPT\n");
        for (int frame = 4; frame <= 32; ++frame) {
            algoPtrF->page_change(frame, page_address);
            algoPtrL->page_change(frame, page_address);
            algoPtrO->page_change(frame, page_address);
            printf("\t%d\t\t %.4f\t\t\t %.4f\t\t\t %.4f\n", frame, 1 - algoPtrF->get_page_invalid_number() / 320,
                   1 - algoPtrL->get_page_invalid_number() / 320, 1 - algoPtrO->get_page_invalid_number() / 320);
        }
    }
};

#endif //OS_03_THE_CLIENT_H

//测试函数,请新建一个任意名称的.cpp文件
#include <iostream>
#include "The_Client.h"

int main() {
    auto *client = new VSM(new OPT(), new FIFO(), new LRU());
    // 生成指令
    client->create_command();
    // 转为页地址流
    client->ToPage_address();
    client->Run();
    return 0;
}

欧耶,至此,实验三已经完成。

由于本人技术有限,代码中不免存在纰漏,还望见谅。💕💕💕

完整虚拟存储管理实验报告!一、实验目的请求页式虚存管理是常用的虚拟存储管理方案之一。通过请求页式虚存管理中对页面置换算法的模拟,有助于理解虚拟存储技术的特点,并加深对请求页式虚存管理的页面调度算法的理解。二、实验环境 Turbo C 2.0/3.0或VC++6.0、实验内容本实验要求使用C语言编程模拟一个拥有若干个虚页的进程在给定的若干个实页中运行、并在缺页中断发生时分别使用FIFO和LRU算法进行页面置换的情形。其中虚页的个数可以事先给定(例如10个),对这些虚页访问的页地址流(其长度可以事先给定,例如20次虚页访问)可以由程序随机产生,也可以事先保存在文件中。要求程序运行时屏幕能显示出置换过程中的状态信息并输出访问结束时的页面命中率。程序应允许通过为该进程分配不同的实页数,来比较两种置换算法的稳定性。四、实验说明 1.设计中虚页和实页的表示本设计利用C语言的结构体来描述虚页和实页的结构。pnpfntimepnpfnnext 虚页结构 实页结构在虚页结构中,pn代表虚页号,因为共10个虚页,所以pn的取值范围是0—9。pfn代表实页号,当一虚页未装入实页时,此项值为-1;当该虚页已装入某一实页时,此项值为所装入的实页的实页号pfn。time项在FIFO算法中不使用,在LRU中用来存放对该虚页的最近访问时间。在实页结构中,pn代表虚页号,表示pn所代表的虚页目前正放在此实页中。pfn代表实页号,取值范围(0—n-1)由动态指派的实页数n所决定。next是一个指向实页结构体的指针,用于多个实页以链表形式组织起来,关于实页链表的组织详见下面第4点。2.关于缺页次数的统计为计算命中率,需要统计在20次的虚页访问中命中的次数。为此,程序应设置一个计数器count,来统计虚页命中发生的次数。每当所访问的虚页的pfn项值不为-1,表示此虚页已被装入某实页内,此虚页被命中,count加1。最终命中率=count/20*100%。3.LRU算法中“最近最久未用”页面的确定为了能找到“最近最久未用”的虚页面,程序中可引入一个时间计数器countime,每当要访问一个虚页面时,countime的值加1,然后将所要访问的虚页的time项值设置为增值后的当前countime值,表示该虚页的最后一次被访问时间。当LRU算法需要置换时,从所有已分配实页的虚页中找出time值为最小的虚页就是“最近最久未用”的虚页面,应该将它置换出去。4.算法中实页的组织因为能分配的实页数n是在程序运行时由用户动态指派的,所以应使用链表组织动态产生的多个实页。为了调度算法实现的方便,可以考虑引入free和busy两个链表:free链表用于组织未分配出去的实页,首指针为free_head,初始时n个实页都处于free链表中;busy链表用于组织已分配出去的实页,首指针为busy_head,尾指针为busy_tail,初始值都为null。当所要访问的一个虚页不在实页中时,将产生缺页中断。此时若free链表不为空,就取下链表首指针所指的实页,并分配给该虚页。若free链表为空,则说明n个实页已全部分配出去,此时应进行页面置换:对于FIFO算法要将busy_head 所指的实页从busy链表中取下,分配给该虚页,然后再将该实页插入到busy链表尾部;对于LRU算法则要从所有已分配实页的虚页中找出time值为最小的虚页,将该虚页从装载它的那个实页中置换出去,并在该实页中装入当前正要访问的虚页。~
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

打代码要笑着打

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值