介绍
就是一个仿真,一般来说这东西知道个原理就差不多了。
但极端需求的情况下可能需要自己实现一个,例如写操作系统的时候。
下边是部分代码
Demo
PT.h
#pragma once
#include <iostream>
#include <vector>
#include <time.h>
class PT
{
public:
typedef struct _PTE
{
//块号
int nFrameNum;
//是否有效
bool bValid;
//
bool bDirty;
//访问次数
int nAccessCount;
}PTE, *PPTE;
enum REPLACEMENT_ALGORITHM
{
OPT = 0,
CLOCK,
FIFO,
RANDOM
};
typedef struct _PHYSICAL
{
char* p;
//OPT算法专用
int nCount;
//CLOCK算法专用
bool bSign;
}PHYSICAL, *PPHYSICAL;
public:
PT();
~PT();
//初始化页表
void Init(int nFrameNum);
//设置页面置换算法
void SetPageReplacement(const char* p);
int MMU(int addr, char type);
//页面替换算法
int PageReplacement();
int PageOPT();
int PageCLOCK();
int PageFIFO();
int PageRandom();
void SwapRead(int nPageNum, int nFrameNum);
void SwapWrite(int nPageNum, int nFrameNum);
private:
std::vector<PTE> m_vPT;
std::vector<PHYSICAL> m_vPhysicalAddr;
std::vector<int> m_vFT;
std::vector<char*> m_vDisk;
REPLACEMENT_ALGORITHM m_pa;
int m_nUsed;
public:
//状态信息
int m_nPageFault;
int m_nWritesToDisk;
int m_nPageNum;
};
PT.cpp
#include "PT.h"
PT::PT()
{
m_nUsed = 0;
m_nPageFault = 0;
m_nWritesToDisk = 0;
m_nPageNum = 0;
}
PT::~PT()
{
}
//初始化页表
void PT::Init(int nFrameNum)
{
//4G / 2K
int nPageSize = 1024 * 2;
m_nPageNum = (1024*1024*1024*1) / (1024 * 2);
for (int i = 0; i < m_nPageNum; i++)
{
//页表项初始化
PTE pte;
pte.nFrameNum = i;
pte.bValid = false;
pte.bDirty = false;
pte.nAccessCount = 0;
m_vPT.push_back(pte);
//磁盘初始化
char* p = new char[nPageSize];
memset(p, 0, nPageSize);
m_vDisk.push_back(p);
}
for (int i = 0; i < nFrameNum; i++)
{
//物理内存初始化
PHYSICAL physical;
physical.nCount = 0;
physical.p = new char[nPageSize];
memset(physical.p, 0, nPageSize);
m_vPhysicalAddr.push_back(physical);
m_vFT.push_back(-1);
}
}
//设置页面置换算法
void PT::SetPageReplacement(const char* p)
{
if (strcmp(p, "opt") == 0)
{
m_pa = OPT;
}
else if (strcmp(p, "clock") == 0)
{
m_pa = CLOCK;
}
else if (strcmp(p, "fifo") == 0)
{
m_pa = FIFO;
}
else if (strcmp(p, "rand") == 0)
{
srand(time(NULL));
m_pa = RANDOM;
}
}
int PT::MMU(int addr, char type)
{
//计算页号和偏移
int nPageNum = addr >> 11;
int nOffset = addr - (nPageNum << 11);
if (nPageNum >= m_vPT.size())
{
//超出内存块
return -1;
}
//获取物理块号
int nFrameNum = 0;
if (m_vPT[nPageNum].bValid == true)
{
nFrameNum = m_vPT[nPageNum].nFrameNum;
}
else
{
nFrameNum = -1;
}
m_vPT[nPageNum].nAccessCount++;
//获取物理地址
int nPhysicalAddr = 0;
if (nFrameNum >= 0)
{
nPhysicalAddr = (int)m_vPhysicalAddr[nFrameNum].p + nOffset;
m_vPhysicalAddr[nFrameNum].bSign = true;
m_vPhysicalAddr[nFrameNum].nCount++;
return nPhysicalAddr;
}
//判断内存块是否没写满
if (m_nUsed < m_vPhysicalAddr.size())
{
//没写满
nFrameNum = m_nUsed;
m_nUsed++;
m_vPT[nPageNum].nFrameNum = nFrameNum;
m_vPT[nPageNum].bValid = true;
m_vPT[nPageNum].bDirty = false;
m_vFT[nFrameNum] = nPageNum;
}
else
{
//写满了 需要页面置换
nFrameNum = PageReplacement();
int nOldPage = m_vFT[nFrameNum];
if (m_vPT[nOldPage].bValid == true)
{
if (m_vPT[nOldPage].bDirty == true)
{
//swap write
SwapWrite(nOldPage, nFrameNum);
}
m_vPT[nOldPage].bValid = false;
m_vPT[nOldPage].bDirty = false;
}
m_vFT[nFrameNum] = nPageNum;
m_vPT[nPageNum].nFrameNum = nFrameNum;
m_vPT[nPageNum].bValid = true;
m_vPT[nPageNum].bDirty = false;
//swap read
SwapRead(nPageNum, nFrameNum);
m_nPageFault++;
}
if (type == 'S' || type == 'M')
{
m_vPT[nPageNum].bDirty = true;
}
nPhysicalAddr = (int)m_vPhysicalAddr[nFrameNum].p + nOffset;
return nPhysicalAddr;
}
//页面替换算法
int PT::PageReplacement()
{
switch (m_pa)
{
case OPT:
return PageOPT();
break;
case CLOCK:
return PageCLOCK();
break;
case FIFO:
return PageFIFO();
break;
case RANDOM:
return PageRandom();
break;
}
return 0;
}
int PT::PageOPT()
{
int nMin = m_vPhysicalAddr[0].nCount;
int nMax = m_vPhysicalAddr[0].nCount;
int nMinIndex = 0;
int nMaxIndex = 0;
for (int i = 0; i < m_vPhysicalAddr.size(); i++)
{
if (nMin > m_vPhysicalAddr[i].nCount)
{
nMin = m_vPhysicalAddr[i].nCount;
nMinIndex = i;
}
if (nMax < m_vPhysicalAddr[i].nCount)
{
nMax = m_vPhysicalAddr[i].nCount;
nMaxIndex = i;
}
}
m_vPhysicalAddr[nMinIndex].nCount = m_vPhysicalAddr[nMaxIndex].nCount + 1;
return nMinIndex;
}
int PT::PageCLOCK()
{
int nIndex = 0;
for (auto it : m_vPhysicalAddr)
{
if (it.bSign == false)
{
break;
}
it.bSign = false;
nIndex++;
}
return 0;
}
int PT::PageFIFO()
{
static int cur = 0;
int next = cur++;
if (cur >= m_vPhysicalAddr.size())
{
cur = 0;
}
return next;
}
int PT::PageRandom()
{
int rd = rand() % m_vPhysicalAddr.size();
return rd;
}
void PT::SwapRead(int nPageNum, int nFrameNum)
{
m_vPhysicalAddr[nFrameNum].p = m_vDisk[nPageNum];
}
void PT::SwapWrite(int nPageNum, int nFrameNum)
{
m_vDisk[nPageNum] = m_vPhysicalAddr[nFrameNum].p;
m_nWritesToDisk++;
}
简单使用
PT pt;
pt.Init(nFrameNum);
pt.SetPageReplacement(strAlgorithm.c_str());
int i = 0;
for (auto it : vIns)
{
pt.MMU(it.addr, it.type);
}