算法过程:
改进型的Clock算法需要综合考虑某一内存页面的访问位和修改位来判断是否置换该页面。在实际编写算法过程中,同样可以用一个等长的整型数组来标识每个内存块的修改状态。访问位A和修改位M可以组成一下四种类型的页面。
1类(A =0, M = 0):表示该页面最近既未被访问,又未被修改,是最佳淘汰页。
2类(A =0, M = 1):表示该页面最近未被访问,但已被修改,并不是很好的淘汰页。
3类(A =1, M = 0):表示该页面最近已被访问,但未被修改,该页有可能再被访问。
4类(A =1, M = 1):表示该页最近已被访问且被修改,该页可能再被访问。
执行步骤如下:
从指针所指示的当前位置开始,扫描循环队列,寻找第一类页面,将所遇到的第一个页面作为所选中的淘汰页。在第一次扫描期间不改变访问位A.
如果第一步失败,即查找一周后未遇到第一类页面,则开始第二轮扫描,寻找第二类页面,将所遇到的第一个这类页面作为淘汰页。在第二轮扫描期间,将所有扫描过的页面的访问位都置0.
如果第二步也失败,亦即未找到第二类页面,则将指针返回到开始位置,并将所有访问位复0.返回第一步。流程如下:
代码示例:
#ifndef PAGEREPLACEMENT_H
#define PAGEREPLACEMENT_H
#include <vector>
class PageReplacement
{
public:
PageReplacement();
~PageReplacement();
void run();
void clockBetter();
private:
void addInfo(const std::vector<int>& modified) const;
private:
int pages; // 虚拟内存的尺寸P
int firstPageFramePos; // 工作面的起始位置p
int pageFrames; // 工作面中包含的页数e
int rateM; // 工作面移动率m
std::vector<int> seqVec; // 序列号
std::vector<int> mem; // 内存块
};
#endif // PAGEREPLACEMENT_H
#include "PageReplacement.h"
#include <iostream>
#include <cstdlib>
#include <list>
PageReplacement::PageReplacement()
: mem(3, -1)
{
this->run();
}
PageReplacement::~PageReplacement()
{
}
void PageReplacement::run()
{
std::cout << "请输入虚拟内存尺寸P:";
std::cin >> pages;
std::cout << "请输入工作面的起始位置p:";
std::cin >> firstPageFramePos;
std::cout << "请输入工作面中包含的页数e:";
std::cin >> pageFrames;
std::cout << "请输入工作面移动率m:";
std::cin >> rateM;
std::cout << "请输入在0和1之间的值t:";
std::cin >> t;
for (int i = 0; i < rateM; ++i)
{
int randomNum = (rand() % pageFrames) + firstPageFramePos;
seqVec.push_back(randomNum);
}
std::cout << "序列号:";
for (int i = 0; i < seqVec.size(); ++i)
{
std::cout << seqVec.at(i) << " ";
}
std::cout << std::endl;
}
void PageReplacement::clockBetter()
{
int nLack = 0; // 缺页数
std::list<int> seqList(seqVec.begin(), seqVec.end());
int nTotal = seqList.size();
std::vector<int> visited(mem.size(), 0);
std::vector<int> modified(mem.size(), 0);
int cursor = 0; // 时钟指针
while (!seqList.empty())
{
int head = *seqList.begin(); // 取队头页面
seqList.pop_front();
int p;
// 遍历内存块,找与队头页面相等的内存块
for (p = 0; p < mem.size(); ++p)
{
if (mem.at(p) == head) // 如果找到, 将其访问位置置1,clock指针循环下移,修改位可能同时被改动
{
visited[p] = 1;
modified[p] = rand() % 2;
cursor = p;
cursor = (cursor + 1) % visited.size();
this->addInfo(modified);
break;
}
}
if (p == mem.size()) // 如果没有找到相等的内存块
{
bool loop = false; // 标识是否继续找被置换的页面
++nLack; // 缺页率加1
// 先找第一类页面,即访问位和修改位都为0
do
{
bool firstClass = false;
for (int i = 0; i < mem.size(); ++i)
{
if (visited[i] == 0 && modified[i] == 0)
{
mem[i] = head; // 置换页面
visited[i] = 1;
cursor = i;
modified[cursor] = rand() % 2; // 修改位可能同时被改动
cursor = (cursor + 1) % visited.size(); // clock 指针循环下移
firstClass = true;
break;
}
}
if (firstClass) //找到了第一类页面
{
this->addInfo(modified);
break;
}
bool secondClass = false; // 如果没找到第一类页面
// 开始找第二类页面,即访问位为0, 修改位为1
for (int i = 0; i < mem.size(); ++i)
{
mem[i] = head; // 置换页面
visited[i] = 1;
cursor = i;
modified[cursor] = rand() % 2;
cursor = (cursor + 1) % visited.size(); // clock 指针循环下移
secondClass = true;
break;
}
if (secondClass) // 找到第二页面
{
this->addInfo(modified);
break;
}
loop = true; // 两类都没找到,重新找第一类
}while (loop);
}
}
// 显示缺页率
std::cout << "缺页率: " << (double)nLack/nTotal * 100 << "%" << std::endl;
}
void PageReplacement::addInfo(const std::vector<int>& modified) const
{
for (int i = 0; i < modified.size(); ++i)
{
if (modified.at(i) == 1)
{
std::cout << mem.at(i) << "@ ";
}
else
{
std::cout << mem.at(i) << " ";
}
}
std::cout << std::endl;
}