操作系统 实验9:页面置换算法模拟设计 (FIFO)(LRU)(OPT)(LFR)(NUR) --使用c++实现 (下)

目录

前言 

核心部分

 先进先出的算法(FIFO)

        代码

        运行

最近最久未使用算法(LRU)

        代码

        运行

最近最少访问页面算法(LFR)

        代码

        运行

最近未用过算法(NUR)

        代码

        运行

最佳页面置换算法(OPT)

        思路

        代码

        运行


前言 

        在上一篇简单介绍了5种算法,和代码总体的设计思路,与c++较c语言优势等。可以点击链接跳转:操作系统 实验9:页面置换算法模拟设计 (FIFO)(LRU)(OPT)(LFR)(NUR) --使用c++实现 (上) - CSDN App】

        这篇博客将深入去看这几种算法的实现,将剩余部分结束。

核心部分

 先进先出的算法(FIFO)

        代码

        这里有关链表的部分,不涉及增删,所以使用静态链表即可,通过索引进行访问。

        先进先出底层就是一个循环单指针队列,通过earliest 指针取余实现循环。一切都非常简单,这是最简单的也是最早出现的页面置换算法。

class FIFO : public User
{
public:
    FIFO(int memSize)
        : User(memSize)
    {
    }

    bool Once(int incId) override
    {
        int pageId = incId / _1K_;
        for (int i = 0; i < memoryCapacity; i++)
        {
            if (pageId == memory[i])
            {
                haveRep = false;
                return haveRep;
            }
        }
        lastRep = memory[earliest];
        memory[earliest] = pageId;
        haveRep = true;
        lastRepNum = earliest;
        earliest = (earliest + 1) % memoryCapacity;
        return haveRep;
    }

private:
    int earliest = 0;

protected:
    std::string Subjoin() const override
    {
        return std::string("\n(FIFO)  现在最早进入的页是第") +
               std::to_string(earliest + 1) + "个";
    }
};

        运行

        主函数在上一篇博客中上过了,这里我直接放运行后的结果了。

最近最久未使用算法(LRU)

        代码

        故名思意,就是在内存当中距离现在-上一次访问在最早之前的页被替换掉,给每个节点定义了一个计时器,与先进先出的算法唯一的不一样就是,一个是选择进入时间最早,一个是选择等待时间最长,其他部分完全一样。

        需要注意的是先进先出算法因为是循环队列,所以完全可以只输出当前指针位置就行了,但是LRU如果只输出指针会非常不直观,所以就以表格对其的方式输出,美观又大气,一目了然。

class LRU : public User // 最近最久未使用算法
{
public:
    LRU(int memSize)
        : User(memSize)
        , time(new int[memSize])
    {
    }

    ~LRU()
    {
        delete[] time;
    }

    bool Once(int incId) override
    {
        int pageId = incId / _1K_;
        haveRep = true;
        for (int i = 0; i < memoryCapacity; i++)
        {
            time[i]++;
            if (pageId == memory[i])
            {
                time[i] = 0;
                haveRep = false;
            }
        }
        if (haveRep)
        {
            int repId = 0;
            for (int i = 1; i < memoryCapacity; i++)
            { // 找到访问时间间隔最大的进行替换
                if (time[i] > time[repId])
                {
                    repId = i;
                }
            }
            lastRepNum = repId;
            lastRep = memory[repId];
            memory[repId] = pageId;
            time[repId] = 0;
        }
        return haveRep;
    }

private:
    int* time; // 上次访问时间间隔

protected:
    std::string Subjoin() const override
    {
        std::string str = "\n(LRU)";
        int width = 3;
        for (int i = 0; i < memoryCapacity; i++)
        {
            str += " | ";
            std::string numberStr = std::to_string(time[i]);
            int padding = 3 - numberStr.length();
            str += std::string(padding, ' ') + numberStr;
        }
        return str + " |  (离上次访问时间)";
    }
};

        运行

最近最少访问页面算法(LFR)

        代码

        LFR和LRU同样也是非常相似,唯一的差别就是一个是记录上一次访问距离现在的时间,一个是记录访问次数。

        放在代码上看就是LRU是被访问的计数归0,其他都要+1,而LFR是被访问的次数+1,其他不变,最低的置换要置1 。

class LFU : public User // 最少使用置换算法
{
public:
    LFU(int memSize)
        : User(memSize)
        , times(new int[memSize])
    {
    }

    ~LFU()
    {
        delete[] times;
    }

    bool Once(int incId) override
    {
        int pageId = incId / _1K_;
        for (int i = 0; i < memoryCapacity; i++)
        {
            if (pageId == memory[i])
            {
                times[i]++;
                haveRep = false;
                return haveRep;
            }
        }
        int repId = 0;
        for (int i = 1; i < memoryCapacity; i++)
        { // 找到访问次数最少的进行替换
            if (times[i] < times[repId])
            {
                repId = i;
            }
        }
        lastRepNum = repId;
        lastRep = memory[repId];
        memory[repId] = pageId;
        times[repId] = 1;
        haveRep = true;
        return haveRep;
    }

private:
    int* times; // 访问次数

protected:
    std::string Subjoin() const override
    {
        std::string str = "\n(LFU)";
        int width = 3;
        for (int i = 0; i < memoryCapacity; i++)
        {
            str += " | ";
            std::string numberStr = std::to_string(times[i]);
            int padding = 3 - numberStr.length();
            str += std::string(padding, ' ') + numberStr;
        }
        return str + " |  (访问次数)";
    }
};

        运行

最近未用过算法(NUR)

        代码

         NUR算法是LFR的改版代码,LFR记录访问次数,而NUR是记录是否在前一个周期中访问过了。LFR的计数器是很多位,但是NUR的是标志位仅仅1位。NUR的一个周期是转一圈,和FIFO一样都是采用循环队列。

        NUR会循环遍历标志位,如果为1则清0,如果为0则置换。

class NRU : public User // 最近未用算法
{
public:
    NRU(int memSize)
        : User(memSize)
        , flag(new bool[memSize])
        , last(0)
    {
        memset(flag, 0, sizeof(bool) * memSize);
    }

    ~NRU()
    {
        delete[] flag;
    }

    bool Once(int incId) override
    {
        int pageId = incId / _1K_;
        for (int i = 0; i < memoryCapacity; i++)
        {
            if (pageId == memory[i])
            {
                flag[i] = true;
                haveRep = false;
                return haveRep;
            }
        }
        while (true)
        {
            last %= memoryCapacity;
            for (; last < memoryCapacity; last++)
            { // 找到标志位为0的进行替换
                if (!flag[last])
                {
                    flag[last] = true;
                    lastRepNum = last;
                    lastRep = memory[last];
                    memory[last] = pageId;
                    haveRep = true;
                    last++;
                    return haveRep;
                }
                else
                    flag[last] = false;
            }
        }
    }

private:
    bool* flag; // 访问标志位
    int last;

protected:
    std::string Subjoin() const override
    {
        std::string str = "\n(NRU)";
        int width = 3;
        for (int i = 0; i < memoryCapacity; i++)
        {
            str += " | ";
            std::string numberStr = std::to_string(flag[i]);
            int padding = 3 - numberStr.length();
            str += std::string(padding, ' ') + numberStr;
        }
        return str + " |  (标志位)";
    }
};

        运行

最佳页面置换算法(OPT)

        最佳页面置换算法是一种基于未来的算法,它不可实现,但是可以作为评估其他页面置换算法的标准。

        选择在最久远未来才会访问的或者以后都不访问了的页进行置换,这样可以最大程度的命中,所以是”最佳“。

        前面的四种算法都是基于过去的,但是这个算法是基于未来的,所以参数需要将未来的所有指令序列传送进来,实现方法页比较复杂,也有其他方法实现,

        思路

        首先需要一个count计数直到当前已经执行到哪一条指令了,从当前指令向后遍历,每一个指令映射的页地址与内存中比较,是否有相同的,有相同的则将标志位标记上已经发现未来需要几步会执行到,直到仅剩下一个未标记的内存中的页,就是最远未来才会遇到的,可以替换掉。如果遍历到结束也没有标记满,说明未被标记的内存页以后再也不会访问,可以替换掉。

        代码

class OPT : public User // 最近未用算法
{
public:
    OPT(int memSize, IncSeq& incSeq)
        : User(memSize)
        , incSeq(incSeq)
        , nextVst(new int[memSize])
    {
        memset(nextVst, -1, sizeof(int) * memoryCapacity);
    }

    ~OPT()
    {
        delete[] nextVst;
    }

    bool Once(int incId) override
    {
        ownCount++;
        int pageId = incId / _1K_;
        for (int i = 0; i < memoryCapacity; i++)
        {
            if (pageId == memory[i])
            {
                haveRep = false;
                return haveRep;
            }
        }
        NextVisit();
        int repId = 0;
        for (int i = 1; i < memoryCapacity; i++)
        { // 找到最久后才访问的进行替换
            if (nextVst[i] < nextVst[repId])
            {
                repId = i;
            }
        }
        lastRepNum = repId;
        lastRep = memory[repId];
        memory[repId] = pageId;
        haveRep = true;
        return haveRep;
    }

private:
    IncSeq& incSeq; // 指令序列
    int* nextVst;
    int ownCount = 0;

    void NextVisit()
    {
        memset(nextVst, -1, sizeof(int) * memoryCapacity);
        bool flag[memoryCapacity];
        memset(flag, 0, sizeof(bool) * memoryCapacity);
        int num = memoryCapacity, ct = ownCount;
        while (num != 1 && ct < incSeq.Size())
        {
            int page = incSeq[ct++] / _1K_;
            for (int i = 0; i < memoryCapacity; i++)
            {
                if (!flag[i] && page == memory[i])
                {
                    flag[i] = true;
                    nextVst[i] = ct - ownCount + 1;
                    num--;
                }
            }
        }
    }

protected:
    std::string Subjoin() const override
    {
        for (int i = 0; i < memoryCapacity; i++)
            if (nextVst[i] > 0)
                nextVst[i]--;
            else if (nextVst[i] == 0)
            {
                nextVst[i] = -2;
                for (int j = ownCount + 1; j < incSeq.Size(); j++)
                {

                    if (memory[i] == incSeq[j] / _1K_)
                    {
                        nextVst[i] = j - ownCount + 1;
                        break;
                    }
                }
            }
        if (haveRep)
        {
            nextVst[lastRepNum] = -1;
            for (int i = ownCount + 1; i < incSeq.Size(); i++)
            {

                if (memory[lastRepNum] == incSeq[i] / _1K_)
                {
                    nextVst[lastRepNum] = i - ownCount;
                    break;
                }
            }
        }
        std::string str = "\n(OPT)";
        int width = 3;
        for (int i = 0; i < memoryCapacity; i++)
        {
            str += " | ";
            std::string numberStr = std::to_string(nextVst[i]);
            int padding = 3 - numberStr.length();
            str += std::string(padding, ' ') + numberStr;
        }
        return str + " |  (到下次访问的距离)";
    }
};

        运行

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Leisure_水中鱼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值