当前位置:   article > 正文

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

opt置换算法模拟

目录

前言 

核心部分

 先进先出的算法(FIFO)

        代码

        运行

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

        代码

        运行

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

        代码

        运行

最近未用过算法(NUR)

        代码

        运行

最佳页面置换算法(OPT)

        思路

        代码

        运行


前言 

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

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

核心部分

 先进先出的算法(FIFO

        代码

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

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

  1. class FIFO : public User
  2. {
  3. public:
  4. FIFO(int memSize)
  5. : User(memSize)
  6. {
  7. }
  8. bool Once(int incId) override
  9. {
  10. int pageId = incId / _1K_;
  11. for (int i = 0; i < memoryCapacity; i++)
  12. {
  13. if (pageId == memory[i])
  14. {
  15. haveRep = false;
  16. return haveRep;
  17. }
  18. }
  19. lastRep = memory[earliest];
  20. memory[earliest] = pageId;
  21. haveRep = true;
  22. lastRepNum = earliest;
  23. earliest = (earliest + 1) % memoryCapacity;
  24. return haveRep;
  25. }
  26. private:
  27. int earliest = 0;
  28. protected:
  29. std::string Subjoin() const override
  30. {
  31. return std::string("\n(FIFO) 现在最早进入的页是第") +
  32. std::to_string(earliest + 1) + "个";
  33. }
  34. };

        运行

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

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

        代码

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

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

  1. class LRU : public User // 最近最久未使用算法
  2. {
  3. public:
  4. LRU(int memSize)
  5. : User(memSize)
  6. , time(new int[memSize])
  7. {
  8. }
  9. ~LRU()
  10. {
  11. delete[] time;
  12. }
  13. bool Once(int incId) override
  14. {
  15. int pageId = incId / _1K_;
  16. haveRep = true;
  17. for (int i = 0; i < memoryCapacity; i++)
  18. {
  19. time[i]++;
  20. if (pageId == memory[i])
  21. {
  22. time[i] = 0;
  23. haveRep = false;
  24. }
  25. }
  26. if (haveRep)
  27. {
  28. int repId = 0;
  29. for (int i = 1; i < memoryCapacity; i++)
  30. { // 找到访问时间间隔最大的进行替换
  31. if (time[i] > time[repId])
  32. {
  33. repId = i;
  34. }
  35. }
  36. lastRepNum = repId;
  37. lastRep = memory[repId];
  38. memory[repId] = pageId;
  39. time[repId] = 0;
  40. }
  41. return haveRep;
  42. }
  43. private:
  44. int* time; // 上次访问时间间隔
  45. protected:
  46. std::string Subjoin() const override
  47. {
  48. std::string str = "\n(LRU)";
  49. int width = 3;
  50. for (int i = 0; i < memoryCapacity; i++)
  51. {
  52. str += " | ";
  53. std::string numberStr = std::to_string(time[i]);
  54. int padding = 3 - numberStr.length();
  55. str += std::string(padding, ' ') + numberStr;
  56. }
  57. return str + " | (离上次访问时间)";
  58. }
  59. };

        运行

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

        代码

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

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

  1. class LFU : public User // 最少使用置换算法
  2. {
  3. public:
  4. LFU(int memSize)
  5. : User(memSize)
  6. , times(new int[memSize])
  7. {
  8. }
  9. ~LFU()
  10. {
  11. delete[] times;
  12. }
  13. bool Once(int incId) override
  14. {
  15. int pageId = incId / _1K_;
  16. for (int i = 0; i < memoryCapacity; i++)
  17. {
  18. if (pageId == memory[i])
  19. {
  20. times[i]++;
  21. haveRep = false;
  22. return haveRep;
  23. }
  24. }
  25. int repId = 0;
  26. for (int i = 1; i < memoryCapacity; i++)
  27. { // 找到访问次数最少的进行替换
  28. if (times[i] < times[repId])
  29. {
  30. repId = i;
  31. }
  32. }
  33. lastRepNum = repId;
  34. lastRep = memory[repId];
  35. memory[repId] = pageId;
  36. times[repId] = 1;
  37. haveRep = true;
  38. return haveRep;
  39. }
  40. private:
  41. int* times; // 访问次数
  42. protected:
  43. std::string Subjoin() const override
  44. {
  45. std::string str = "\n(LFU)";
  46. int width = 3;
  47. for (int i = 0; i < memoryCapacity; i++)
  48. {
  49. str += " | ";
  50. std::string numberStr = std::to_string(times[i]);
  51. int padding = 3 - numberStr.length();
  52. str += std::string(padding, ' ') + numberStr;
  53. }
  54. return str + " | (访问次数)";
  55. }
  56. };

        运行

最近未用过算法(NUR)

        代码

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

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

  1. class NRU : public User // 最近未用算法
  2. {
  3. public:
  4. NRU(int memSize)
  5. : User(memSize)
  6. , flag(new bool[memSize])
  7. , last(0)
  8. {
  9. memset(flag, 0, sizeof(bool) * memSize);
  10. }
  11. ~NRU()
  12. {
  13. delete[] flag;
  14. }
  15. bool Once(int incId) override
  16. {
  17. int pageId = incId / _1K_;
  18. for (int i = 0; i < memoryCapacity; i++)
  19. {
  20. if (pageId == memory[i])
  21. {
  22. flag[i] = true;
  23. haveRep = false;
  24. return haveRep;
  25. }
  26. }
  27. while (true)
  28. {
  29. last %= memoryCapacity;
  30. for (; last < memoryCapacity; last++)
  31. { // 找到标志位为0的进行替换
  32. if (!flag[last])
  33. {
  34. flag[last] = true;
  35. lastRepNum = last;
  36. lastRep = memory[last];
  37. memory[last] = pageId;
  38. haveRep = true;
  39. last++;
  40. return haveRep;
  41. }
  42. else
  43. flag[last] = false;
  44. }
  45. }
  46. }
  47. private:
  48. bool* flag; // 访问标志位
  49. int last;
  50. protected:
  51. std::string Subjoin() const override
  52. {
  53. std::string str = "\n(NRU)";
  54. int width = 3;
  55. for (int i = 0; i < memoryCapacity; i++)
  56. {
  57. str += " | ";
  58. std::string numberStr = std::to_string(flag[i]);
  59. int padding = 3 - numberStr.length();
  60. str += std::string(padding, ' ') + numberStr;
  61. }
  62. return str + " | (标志位)";
  63. }
  64. };

        运行

最佳页面置换算法(OPT)

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

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

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

        思路

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

        代码

  1. class OPT : public User // 最近未用算法
  2. {
  3. public:
  4. OPT(int memSize, IncSeq& incSeq)
  5. : User(memSize)
  6. , incSeq(incSeq)
  7. , nextVst(new int[memSize])
  8. {
  9. memset(nextVst, -1, sizeof(int) * memoryCapacity);
  10. }
  11. ~OPT()
  12. {
  13. delete[] nextVst;
  14. }
  15. bool Once(int incId) override
  16. {
  17. ownCount++;
  18. int pageId = incId / _1K_;
  19. for (int i = 0; i < memoryCapacity; i++)
  20. {
  21. if (pageId == memory[i])
  22. {
  23. haveRep = false;
  24. return haveRep;
  25. }
  26. }
  27. NextVisit();
  28. int repId = 0;
  29. for (int i = 1; i < memoryCapacity; i++)
  30. { // 找到最久后才访问的进行替换
  31. if (nextVst[i] < nextVst[repId])
  32. {
  33. repId = i;
  34. }
  35. }
  36. lastRepNum = repId;
  37. lastRep = memory[repId];
  38. memory[repId] = pageId;
  39. haveRep = true;
  40. return haveRep;
  41. }
  42. private:
  43. IncSeq& incSeq; // 指令序列
  44. int* nextVst;
  45. int ownCount = 0;
  46. void NextVisit()
  47. {
  48. memset(nextVst, -1, sizeof(int) * memoryCapacity);
  49. bool flag[memoryCapacity];
  50. memset(flag, 0, sizeof(bool) * memoryCapacity);
  51. int num = memoryCapacity, ct = ownCount;
  52. while (num != 1 && ct < incSeq.Size())
  53. {
  54. int page = incSeq[ct++] / _1K_;
  55. for (int i = 0; i < memoryCapacity; i++)
  56. {
  57. if (!flag[i] && page == memory[i])
  58. {
  59. flag[i] = true;
  60. nextVst[i] = ct - ownCount + 1;
  61. num--;
  62. }
  63. }
  64. }
  65. }
  66. protected:
  67. std::string Subjoin() const override
  68. {
  69. for (int i = 0; i < memoryCapacity; i++)
  70. if (nextVst[i] > 0)
  71. nextVst[i]--;
  72. else if (nextVst[i] == 0)
  73. {
  74. nextVst[i] = -2;
  75. for (int j = ownCount + 1; j < incSeq.Size(); j++)
  76. {
  77. if (memory[i] == incSeq[j] / _1K_)
  78. {
  79. nextVst[i] = j - ownCount + 1;
  80. break;
  81. }
  82. }
  83. }
  84. if (haveRep)
  85. {
  86. nextVst[lastRepNum] = -1;
  87. for (int i = ownCount + 1; i < incSeq.Size(); i++)
  88. {
  89. if (memory[lastRepNum] == incSeq[i] / _1K_)
  90. {
  91. nextVst[lastRepNum] = i - ownCount;
  92. break;
  93. }
  94. }
  95. }
  96. std::string str = "\n(OPT)";
  97. int width = 3;
  98. for (int i = 0; i < memoryCapacity; i++)
  99. {
  100. str += " | ";
  101. std::string numberStr = std::to_string(nextVst[i]);
  102. int padding = 3 - numberStr.length();
  103. str += std::string(padding, ' ') + numberStr;
  104. }
  105. return str + " | (到下次访问的距离)";
  106. }
  107. };

        运行

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号