FIFO和LRU算法实现操作系统中主存管理
FIFO,用数组实现
1和2都是使用nextReplace实现新页面位置的更新
1、不精确时间:用ctime输出运行时间都是0.00秒
#include <iostream>
#include <iomanip>
#include<ctime>//用于计算时间
using namespace std;
// 页访问顺序
int pages[20] = { 7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1 };
// FIFO算法
void fifo(int n) {
int memory[5] = { -1, -1, -1, -1, -1 }; // 用于存储主存块,初始化为 -1 表示空
int table[5][20] = { -1 }; // 用于记录每次访问的内存状态,初始化为 -1 表示空
bool status[20]; // 记录是否缺页
int pageFaults = 0; // 缺页次数
int nextReplace = 0; // 记录下一个要替换的位置
// 获取开始时间(时钟周期数)
clock_t start = clock();
// 遍历每个页面访问
for (int j = 0; j < 20; j++) {
int page = pages[j];
bool found = false;
// 检查页面是否已在内存中
for (int i = 0; i < n; i++) {
if (memory[i] == page) {
found = true;
break;
}
}
if (!found) { // 缺页情况
memory[nextReplace] = page; // 替换页面
nextReplace = (nextReplace + 1) % n; // 更新替换位置
status[j] = false; // 标记缺页
pageFaults++;
}
else {
status[j] = true; // 标记命中
}
// 记录当前内存状态到表格
for (int i = 0; i < n; i++) {
table[i][j] = memory[i];
}
}
// 获取结束时间(时钟周期数)
clock_t end = clock();
// 输出结果表格
cout << "主存块号 ";
for (int j = 0; j < 20; j++) {
cout << pages[j] << " ";
}
cout << endl;
for (int i = 0; i < n; i++) {
cout << " " << i << " ";
for (int j = 0; j < 20; j++) {
if (table[i][j] == -1) {
cout << " "; // 空块显示为空格
}
else {
cout << table[i][j] << " ";
}
}
cout << endl;
}
// 输出缺页标记
cout << "是否缺页 ";
for (int j = 0; j < 20; j++) {
if (status[j]) {
cout << "\u221A "; // Unicode "√"
}
else {
cout << "\u00D7 "; // Unicode "×"
}
}
cout << endl;
cout << "FIFO 缺页率: " << fixed << setprecision(2) << (float)pageFaults / 20 * 100 << "%" << endl;
cout << "运行时间: " << (double)(end - start) / CLOCKS_PER_SEC << " 秒" << endl; // 输出运行时间
}
int main() {
cout << "内存容量为 3 块:\n";
fifo(3);
cout << endl;
cout << "内存容量为 4 块:\n";
fifo(4);
return 0;
}
2、精确时间:用chrono输出运行时间都是xx微秒,输出时间不定
#include <iostream>
#include <iomanip>
#include <chrono> // 引入chrono库
using namespace std;
using namespace std::chrono; // 使用chrono命名空间
// 页访问顺序
int pages[20] = { 7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1 };
// FIFO算法
void fifo(int n) {
int memory[5] = { -1, -1, -1, -1, -1 }; // 用于存储主存块,初始化为 -1 表示空
int table[5][20] = { -1 }; // 用于记录每次访问的内存状态,初始化为 -1 表示空
bool status[20]; // 记录是否缺页
int pageFaults = 0; // 缺页次数
int nextReplace = 0; // 记录下一个要替换的位置
// 获取开始时间
auto start = high_resolution_clock::now();
// 遍历每个页面访问
for (int j = 0; j < 20; j++) {
int page = pages[j];
bool found = false;
// 检查页面是否已在内存中
for (int i = 0; i < n; i++) {
if (memory[i] == page) {
found = true;
break;
}
}
if (!found) { // 缺页情况
memory[nextReplace] = page; // 替换页面
nextReplace = (nextReplace + 1) % n; // 更新替换位置
status[j] = false; // 标记缺页
pageFaults++;
}
else {
status[j] = true; // 标记命中
}
// 记录当前内存状态到表格
for (int i = 0; i < n; i++) {
table[i][j] = memory[i];
}
}
// 获取结束时间
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
// 输出结果表格
cout << "主存块号 ";
for (int j = 0; j < 20; j++) {
cout << pages[j] << " ";
}
cout << endl;
for (int i = 0; i < n; i++) {
cout << " " << i << " ";
for (int j = 0; j < 20; j++) {
if (table[i][j] == -1) {
cout << " "; // 空块显示为空格
}
else {
cout << table[i][j] << " ";
}
}
cout << endl;
}
// 输出缺页标记
cout << "是否缺页 ";
for (int j = 0; j < 20; j++) {
if (status[j]) {
cout << "\u221A "; // Unicode "√"
}
else {
cout << "\u00D7 "; // Unicode "×"
}
}
cout << endl;
cout << "FIFO 缺页率: " << fixed << setprecision(2) << (float)pageFaults / 20 * 100 << "%" << endl;
cout << "运行时间: " << duration.count() << " 微秒" << endl; // 输出运行时间
}
int main() {
cout << "内存容量为 3 块:\n";
fifo(3);
cout << endl;
cout << "内存容量为 4 块:\n";
fifo(4);
return 0;
}
3、数组模拟队列、类似滑动窗口
#include <iostream>
#include <iomanip>
#include <chrono>
#include <cstring>
using namespace std;
using namespace std::chrono;
const int N = 1010;
int memory[N];//每次查找页面进行记录的滑动窗口
int table[5][20]; // 最终输出的表格状态
// 页访问顺序
int pages[20] = { 7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1 };
// FIFO算法
void fifo(int n) {
memset(memory, 0x3f, sizeof memory);
bool status[20]; // 记录是否缺页
int pageFaults = 0; // 缺页次数
int hh = 0, tt = -1; // 队首和队尾指针
auto start = high_resolution_clock::now(); // 获取开始时间
for (int j = 0; j < 20; j++) {
int page = pages[j];
bool found = false;
// 检查页面是否已在内存中
for (int i = hh; i <= tt; i++) {
if (memory[i] == page) {
found = true;
break;
}
}
if (!found) { // 缺页情况
memory[++tt] = page; // 新页面加入队尾
// 控制滑动窗口大小为 n
if (tt - hh + 1 > n) {
hh++; // 超过容量,队首出队
}
status[j] = false; // 标记缺页
pageFaults++;
}
else {
status[j] = true; // 标记命中
}
// 记录当前内存状态到表格
for (int i = 0; i < n; i++) {
//如果只写memory[hh]的话不就移动队首指针了吗,不可以,现在是赋值阶段,只需要控制负责赋值的滑动指针首先不能超过队尾指针,确保在滑动窗口范围内,
//因为有可能这个滑动窗口不足n长,你就会多余赋值本来不能存在的页面号赋值成0x3f,其次需要满足当前检查是否缺页的一次记录memory,该位置是否有值
if (i + hh <= tt && memory[i + hh] != 0x3f) {
table[i][j] = memory[i + hh];
}
else {
table[i][j] = -1; // 空位显示为 -1
}
}
}
auto stop = high_resolution_clock::now(); // 获取结束时间
auto duration = duration_cast<microseconds>(stop - start);
// 输出结果表格
cout << "主存块号 ";
for (int j = 0; j < 20; j++) {
cout << pages[j] << " ";
}
cout << endl;
for (int i = 0; i < n; i++) {
cout << " " << i << " ";
for (int j = 0; j < 20; j++) {
if (table[i][j] == -1) {
cout << " "; // 空块显示为空格
}
else {
cout << table[i][j] << " ";
}
}
cout << endl;
}
// 输出缺页标记
cout << "是否缺页 ";
for (int j = 0; j < 20; j++) {
cout << (status[j] ? "\u221A " : "\u00D7 ");//unicode编码,前者代表true则不缺页是√标识,后者代表false是缺页×表示
}
cout << endl;
cout << "FIFO 缺页率: " << fixed << setprecision(2) << (float)pageFaults / 20 * 100 << "%" << endl;
cout << "运行时间: " << duration.count() << " 微秒" << endl;
}
int main() {
cout << "内存容量为 3 块:\n";
fifo(3);
cout << endl;
cout << "内存容量为 4 块:\n";
fifo(4);
return 0;
}
朴素版算缺页率
#include <iostream>
#include <ctime>
#include <cstring>
using namespace std;
const int N = 1010;
int memory[N];//每次查找页面进行记录的滑动窗口
int table[5][20]; // 最终输出的表格状态
// 页访问顺序
int pages[20] = { 7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1 };
// FIFO算法
void fifo(int n) {
memset(memory, 0x3f, sizeof memory);
bool status[20]; // 记录是否缺页
int pageFaults = 0; // 缺页次数
int hh = 0, tt = -1; // 队首和队尾指针
clock_t start=clock(); // 获取开始时间
for (int j = 0; j < 20; j++) {
int page = pages[j];
bool found = false;
// 检查页面是否已在内存中
for (int i = hh; i <= tt; i++) {
if (memory[i] == page) {
found = true;
break;
}
}
if (!found) { // 缺页情况
memory[++tt] = page; // 新页面加入队尾
// 控制滑动窗口大小为 n
if (tt - hh + 1 > n) {
hh++; // 超过容量,队首出队
}
status[j] = false; // 标记缺页
pageFaults++;
}
else {
status[j] = true; // 标记命中
}
// 记录当前内存状态到表格
for (int i = 0; i < n; i++) {
//如果只写memory[hh]的话不就移动队首指针了吗,不可以,现在是赋值阶段,只需要控制负责赋值的滑动指针首先不能超过队尾指针,确保在滑动窗口范围内,
//因为有可能这个滑动窗口不足n长,你就会多余赋值本来不能存在的页面号赋值成0x3f,其次需要满足当前检查是否缺页的一次记录memory,该位置是否有值
if (i + hh <= tt && memory[i + hh] != 0x3f) {
table[i][j] = memory[i + hh];
}
else {
table[i][j] = -1; // 空位显示为 -1
}
}
}
clock_t end = clock(); // 获取结束时间
// 输出结果表格
cout << "主存块号 ";
for (int j = 0; j < 20; j++) {
cout << pages[j] << " ";
}
cout << endl;
for (int i = 0; i < n; i++) {
cout << " " << i << " ";
for (int j = 0; j < 20; j++) {
if (table[i][j] == -1) {
cout << " "; // 空块显示为空格
}
else {
cout << table[i][j] << " ";
}
}
cout << endl;
}
// 输出缺页标记
cout << "是否缺页 ";
for (int j = 0; j < 20; j++) {
cout << (status[j] ? "\u221A " : "\u00D7 ");//unicode编码,前者代表true则不缺页是√标识,后者代表false是缺页×表示
}
cout << endl;
cout << "FIFO 缺页率: " << (float)pageFaults / 20 * 100 << "%" << endl;
cout << "运行时间: " << (double)(end-start)/CLOCKS_PER_SEC << " 秒" << endl;
}
int main() {
cout << "内存容量为 3 块:\n";
fifo(3);
cout << endl;
cout << "内存容量为 4 块:\n";
fifo(4);
return 0;
}
FIFO,用链表实现
LRU,用计数器实现
#include <iostream>
#include <ctime>
#include <cstring>
#include <unordered_map>
using namespace std;
const int N = 1010;
int table[5][20]; // 最终输出的表格状态
unordered_map<int, int> m; // 键为page号,值为count值
int pages[20] = { 7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1 };
void lru(int n) {
memset(table, -1, sizeof table);
m.clear();
bool status[20]; // 记录是否缺页
int pageFaults = 0; // 缺页次数
clock_t start = clock(); // 获取开始时间
for (int j = 0; j < 20; j++) {
int page = pages[j];
if (!m.count(page)) { // 没命中就要加入或者替换页面
if (m.size() >= n) {
// 找到count最大的页面进行替换
int maxpage = -1, maxcounts = -1;
for (auto p : m) {
if (p.second > maxcounts) {
maxpage = p.first;
maxcounts = p.second;
}
}
m.erase(maxpage);
}
m[page] = 0;//没命中且主存没满则直接加入页面
pageFaults++;
status[j] = false; // 标记缺页
}
else {
status[j] = true; // 标记命中
m[page] = 0;
}
// 更新所有页面的count值:命中则置0,没命中加入新页面——满足条件则不加1即可,不管加不加入新页面,其他没中的页面都是要count+1的
for (auto& p : m) {
if (p.first != page) {
p.second += 1;
}
}
// 更新当前主存块内存在的页面
int i = 0;
for (auto p : m) {
if (i < n) {//用一个i去便利贮存块,而不用for
table[i][j] = p.first;
i++;
}
}
//一开始写错了:
/*for (int i = 0; i < n; i++) {
for (auto p : m) {
table[i][j] = p.first;
}
}*/
}
clock_t end = clock(); // 获取结束时间
// 输出结果表格
cout << "主存块号 ";
for (int j = 0; j < 20; j++) {
cout << pages[j] << " ";
}
cout << endl;
for (int i = 0; i < n; i++) {
cout << " " << i << " ";
for (int j = 0; j < 20; j++) {
if (table[i][j] == -1) {
cout << " "; // 空块显示为空格
}
else {
cout << table[i][j] << " ";
}
}
cout << endl;
}
// 输出缺页标记
cout << "是否缺页 ";
for (int j = 0; j < 20; j++) {
cout << (status[j] ? "\u221A " : "\u00D7 ");
}
cout << endl;
cout << "LRU 缺页率: " << (float)(pageFaults) / 20 * 100 << "%" << endl;
cout << "运行时间: " << (double)(end - start) / CLOCKS_PER_SEC << " 秒" << endl;
}
int main() {
cout << "内存容量为 3 块:\n";
lru(3);
cout << endl;
cout << "内存容量为 4 块:\n";
lru(4);
return 0;
}
LRU,用堆栈实现
两个算法综合在一起看运行速率
#include <iostream>
#include <ctime>
#include <cstring>
#include <unordered_map>
#include <chrono> // 引入chrono库
using namespace std;
using namespace std::chrono; // 使用chrono命名空间
const int N = 1010;
int table[5][20]; // 最终输出的表格状态
unordered_map<int, int> m; // 键为page号,值为count值
int pages[20] = { 7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1 };
int memory[N];//每次查找页面进行记录的滑动窗口
// FIFO算法
void fifo(int n) {
memset(memory, 0x3f, sizeof memory);
memset(table, -1, sizeof table);
bool status[20]; // 记录是否缺页
int pageFaults = 0; // 缺页次数
int hh = 0, tt = -1; // 队首和队尾指针
//clock_t start = clock(); // 获取开始时间
// 获取开始时间
auto start = high_resolution_clock::now();
for (int j = 0; j < 20; j++) {
int page = pages[j];
bool found = false;
// 检查页面是否已在内存中
for (int i = hh; i <= tt; i++) {
if (memory[i] == page) {
found = true;
break;
}
}
if (!found) { // 缺页情况
memory[++tt] = page; // 新页面加入队尾
// 控制滑动窗口大小为 n
if (tt - hh + 1 > n) {
hh++; // 超过容量,队首出队
}
status[j] = false; // 标记缺页
pageFaults++;
}
else {
status[j] = true; // 标记命中
}
// 记录当前内存状态到表格
for (int i = 0; i < n; i++) {
//如果只写memory[hh]的话不就移动队首指针了吗,不可以,现在是赋值阶段,只需要控制负责赋值的滑动指针首先不能超过队尾指针,确保在滑动窗口范围内,
//因为有可能这个滑动窗口不足n长,你就会多余赋值本来不能存在的页面号赋值成0x3f,其次需要满足当前检查是否缺页的一次记录memory,该位置是否有值
if (i + hh <= tt && memory[i + hh] != 0x3f) {
table[i][j] = memory[i + hh];
}
else {
table[i][j] = -1; // 空位显示为 -1
}
}
}
//clock_t end = clock(); // 获取结束时间
// 获取结束时间
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
// 输出结果表格
cout << "主存块号 ";
for (int j = 0; j < 20; j++) {
cout << pages[j] << " ";
}
cout << endl;
for (int i = 0; i < n; i++) {
cout << " " << i << " ";
for (int j = 0; j < 20; j++) {
if (table[i][j] == -1) {
cout << " "; // 空块显示为空格
}
else {
cout << table[i][j] << " ";
}
}
cout << endl;
}
// 输出缺页标记
cout << "是否缺页 ";
for (int j = 0; j < 20; j++) {
cout << (status[j] ? "\u221A " : "\u00D7 ");//unicode编码,前者代表true则不缺页是√标识,后者代表false是缺页×表示
}
cout << endl;
cout << "FIFO 缺页率: " << (float)pageFaults / 20 * 100 << "%" << endl;
//cout << "运行时间: " << (double)(end - start) / CLOCKS_PER_SEC << " 秒" << endl;
cout << "运行时间: " << duration.count() << " 微秒" << endl; // 输出运行时间
}
void lru(int n) {
memset(table, -1, sizeof table);
m.clear();
bool status[20]; // 记录是否缺页
int pageFaults = 0; // 缺页次数
//clock_t start = clock(); // 获取开始时间
// 获取开始时间
auto start = high_resolution_clock::now();
for (int j = 0; j < 20; j++) {
int page = pages[j];
if (!m.count(page)) { // 没命中就要加入或者替换页面
if (m.size() >= n) {
// 找到count最大的页面进行替换
int maxpage = -1, maxcounts = -1;
for (auto p : m) {
if (p.second > maxcounts) {
maxpage = p.first;
maxcounts = p.second;
}
}
m.erase(maxpage);
}
m[page] = 0;//没命中且主存没满则直接加入页面
pageFaults++;
status[j] = false; // 标记缺页
}
else {
status[j] = true; // 标记命中
m[page] = 0;
}
// 更新所有页面的count值:命中则置0,没命中加入新页面——满足条件则不加1即可,不管加不加入新页面,其他没中的页面都是要count+1的
for (auto& p : m) {
if (p.first != page) {
p.second += 1;
}
}
// 更新当前主存块内存在的页面
int i = 0;
for (auto p : m) {
if (i < n) {//用一个i去便利贮存块,而不用for
table[i][j] = p.first;
i++;
}
}
//一开始写错了:
/*for (int i = 0; i < n; i++) {
for (auto p : m) {
table[i][j] = p.first;
}
}*/
}
//clock_t end = clock(); // 获取结束时间
// 获取结束时间
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
// 输出结果表格
cout << "主存块号 ";
for (int j = 0; j < 20; j++) {
cout << pages[j] << " ";
}
cout << endl;
for (int i = 0; i < n; i++) {
cout << " " << i << " ";
for (int j = 0; j < 20; j++) {
if (table[i][j] == -1) {
cout << " "; // 空块显示为空格
}
else {
cout << table[i][j] << " ";
}
}
cout << endl;
}
// 输出缺页标记
cout << "是否缺页 ";
for (int j = 0; j < 20; j++) {
cout << (status[j] ? "\u221A " : "\u00D7 ");
}
cout << endl;
cout << "LRU 缺页率: " << (float)(pageFaults) / 20 * 100 << "%" << endl;
//cout << "运行时间: " << (double)(end - start) / CLOCKS_PER_SEC << " 秒" << endl;
cout << "运行时间: " << duration.count() << " 微秒" << endl; // 输出运行时间
}
int main() {
cout << "内存容量为 3 块:\n";
fifo(3);
cout << endl;
lru(3);
cout << endl;
cout << "内存容量为 4 块:\n";
fifo(4);
cout << endl;
lru(4);
return 0;
}
1)主存块数越多的,不论哪个算法,运行时间都更长一些,用的时chrono精确时间微妙
但是同样的,运行每次的时间不定
2)主存块数越多的,不论哪个算法,缺页率都更低一些