赞
踩
目录
在上一篇简单介绍了5种算法,和代码总体的设计思路,与c++较c语言优势等。可以点击链接跳转:操作系统 实验9:页面置换算法模拟设计 (FIFO)(LRU)(OPT)(LFR)(NUR) --使用c++实现 (上) - CSDN App】
这篇博客将深入去看这几种算法的实现,将剩余部分结束。
这里有关链表的部分,不涉及增删,所以使用静态链表即可,通过索引进行访问。
先进先出底层就是一个循环单指针队列,通过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如果只输出指针会非常不直观,所以就以表格对其的方式输出,美观又大气,一目了然。
- 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和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算法是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 + " | (标志位)";
- }
- };
最佳页面置换算法是一种基于未来的算法,它不可实现,但是可以作为评估其他页面置换算法的标准。
选择在最久远未来才会访问的或者以后都不访问了的页进行置换,这样可以最大程度的命中,所以是”最佳“。
前面的四种算法都是基于过去的,但是这个算法是基于未来的,所以参数需要将未来的所有指令序列传送进来,实现方法页比较复杂,也有其他方法实现,
首先需要一个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 + " | (到下次访问的距离)";
- }
- };
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。