操作系统之内存管理_页面置换算法(C++实现LRU)

一、问题描述
在这里插入图片描述
场景
假定系统为某进程分配了3个物理块,并考虑有页面号引用串{7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1}。
若采用LRU算法进行页面置换,如上图所示,进程第一次对页面2访问时,将最近最久未被访问的页面7置换出去,然后再访问3时,将最近最久未使用的页面1置换出去。

现采用C++实现LRU,模拟上述过程

二、C++实现LRU
1.预备知识
(1)LRU : Least Recently Used 最近最少使用
(2)选用的数据结构
①由于需要查找物理块中是否已有要访问的页面,选用map(内部用红黑树实现),其查找元素的时间复杂度为O( log ⁡ 2 N \log_2N log2N);

map<int, CacheNode *> mp; //int,页面号;CacheNode *, 对应结点的地址

②由于需要插入和删除,若选用单链表将结点链接起来,删除结点的时候需要从表头开始遍历查找,时间复杂度为O(n);而采用双链表,时间复杂度为O(1)

struct CacheNode {
            int key;
            int value;
            CacheNode *pre, *next;
            CacheNode(int k, int v) : key(k), value(v), pre(nullptr), next(nullptr) {}
        };

故选择map + 双链表实现LRU

(3)涉及的操作
①新插入的结点应放置在双链表的头部(setHead函数)
②成功访问双链表的结点,需将该结点移至双链表的头部(remove函数 + setHead函数)
③若链表已满,则丢弃链表尾部结点(remove函数)

setHead函数的代码:

void setHead(CacheNode *node) {
            node->next = head;
            node->pre = nullptr;
            if(head != nullptr) 
                head->pre = node;
            head = node;
            if(tail == nullptr)
                tail = head;
        }

remove函数的代码:

void remove(CacheNode *node) {
            if(node->pre != nullptr)
                node->pre->next = node->next;
            else 
                head = node->next;
            if (node->next != nullptr)
                node->next->pre = node->pre;
            else
                tail = node->pre;
        }

实现①~③的代码:

void set(int key, int value) {
            map<int, CacheNode *>::iterator it = mp.find(key);
            if(it != mp.end()) {
                CacheNode *node = it->second;
                node->value = value;
                remove(node);
                setHead(node);
            }
            else {
                CacheNode *newNode = new CacheNode(key, value);
                if(mp.size() == size) {
                    map<int, CacheNode *>::iterator it = mp.find(tail->key);
                    remove(tail);
                    mp.erase(it);
                }
                setHead(newNode);
                mp[key] = newNode;
            }
        }

三、完整代码及运行结果
1.完整代码

//C++实现LRU
#include <map>
#include <iostream>
#include <cstdio>
using namespace std;
typedef unsigned int UI;
class LRUCache {
    private:
        struct CacheNode {
            int key;
            int value;
            CacheNode *pre, *next;
            CacheNode(int k, int v) : key(k), value(v), pre(nullptr), next(nullptr) {}
        };  
        UI size;
        CacheNode *head, *tail;
        map<int, CacheNode *> mp;

    public:
        LRUCache(int capacity) : size(capacity), head(nullptr), tail(nullptr) {}
        void setHead(CacheNode *node) {
            node->next = head;
            node->pre = nullptr;
            if(head != nullptr) 
                head->pre = node;
            head = node;
            if(tail == nullptr)
                tail = head;
        }
        void remove(CacheNode *node) {
            if(node->pre != nullptr)
                node->pre->next = node->next;
            else 
                head = node->next;
            if (node->next != nullptr)
                node->next->pre = node->pre;
            else
                tail = node->pre;
        }
        void set(int key, int value) {
            map<int, CacheNode *>::iterator it = mp.find(key);
            if(it != mp.end()) {
                CacheNode *node = it->second;
                node->value = value;
                remove(node);
                setHead(node);
            }
            else {
                CacheNode *newNode = new CacheNode(key, value);
                if(mp.size() == size) {
                    map<int, CacheNode *>::iterator it = mp.find(tail->key);
                    remove(tail);
                    mp.erase(it);
                }
                setHead(newNode);
                mp[key] = newNode;
            }
        }
        //本次模拟无需get函数
        int get(int key) {
            map<int, CacheNode *>::iterator it = mp.find(key);
            if(it != mp.end()) {
                CacheNode *node = it->second;
                remove(node);
                setHead(node);
                return node->value;
            }
            else
                return -1;
        }   
};

int main() {
    //测试 3个物理块 访问页面 : 7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1
    LRUCache *lruCache = new LRUCache(3);
    int sequence[] = {7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3, 2, 1, 2, 0, 1, 7, 0, 1};
    const int value = 7; //页面内容,非模拟重点,都设为7;
    int len = sizeof(sequence) / sizeof(sequence[0]);
    int count = 0;
    for (int i = 0; i < len; i++) {
        if(lruCache->get(sequence[i]) == -1) {
            //缺页
            count++;
            printf("%d号页面缺失\n", sequence[i]);
            lruCache->set(sequence[i], value);
        }
        else {
            printf("%d号页面命中\n", sequence[i]);
        }
    }
    printf("总共缺页次数为%d\n", count);
    return 0;
}

2.运行结果
在这里插入图片描述
四、参考文献
常见缓存算法和LRU的c++实现

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本实验使用一下算法 使用rand()函数随机产生页面号,用数组装入页面号,模拟页面调入内存中发生页面置换的过程。 整个过程,都是使用数组来实现每个算法,模拟队列,模拟堆栈的功能,实现每一个置换算法页面置换算法 最佳置换算法(OPT):选择永不使用或是在最长时间内不再被访问(即距现在最长时间才会被访问)的页面淘汰出内存。用于算法评价参照。 随机置换算法 (S):产生一个取值范围在0和N-1之间的随机数,该随机数即可表示应被淘汰出内存的页面。 先进先出置换算法(FIFO):选择最先进入内存即在内存驻留时间最久的页面换出到外存。 最近最久未使用置换算法LRU): 以“最近的过去”作为“最近的将来”的近似,选择最近一段时间最长时间未被访问的页面淘汰出内存 Clock置换算法:为进入内存的页面设置一个访问位,当内存中某页被访问,访问位置一,算法在选择一页淘汰时,只需检查访问位,若为0,则直接换出,若为1,置该访问位为0,检测内存中的下一个页面的访问位。 改进型Clock置换算法: ①从查寻指针当前位置起扫描内存分页循环队列,选择A=0且M=0的第一个页面淘汰;若未找到,转② ② 开始第二轮扫描,选择A=0且M=1的第一个页面淘汰,同时将经过的所有页面访问位置0;若不能找到,转①
时钟算法 页面置换算法 #pragma once #include <iostream> #include "Pclass.h" using namespace std; class Allocation { private: int pnum;//页面数 int bnum;//分配块数 //int ID; int num;//访问页面次数 Pclass * block;//块数组 int *page;//页访问顺序 //int p; public: Allocation(int pn,int bl,int n) { pnum=pn; bnum=bl; num=n; //ID=id; block=new Pclass [bnum]; page=new int [num]; cout<<"页面访问顺序:"; for(int i=0;i<num;i++) { page[i]=rand()%pnum+1; cout<<page[i]<<" "; } cout<<endl; //p=0; } void FIFO() { cout<<"先进先出算法:"<<endl; int p=0; int nm=0; for(int i=0;i<num;i++) { if(Haven(page[i])!=(-1)) { nm++; } else { block[p].num=page[i]; p=(++p)%bnum; } for(int j=0;j<bnum;j++) { if(block[j].num!=0) { cout<<block[j].num<<" "; } } cout<<endl; } cout<<"命中率为:"<<(double)nm/(double)num<<endl; } int Haven(int n) { for(int i=0;i<bnum;i++) { if(block[i].num==n) { return i; } } return -1; } void LRU() { int p=0; int nm=0; for(int i=0;i<bnum;i++) { block[i].num=0; block[i].visited=false; } for(int i=0;i<num;i++) { int temp=Haven(page[i]); if(temp!=(-1)) { block[temp].visited=true; nm++; } else { //int j=0; while(1) { if(block[p].visited==false) { block[p].num=page[i]; p=(++p)%bnum; break; } else { block[p].visited=false; p=(++p)%bnum; } } } for(int j=0;j<bnum;j++) { if(block[j].num!=0) { cout<<block[j].num<<" "; } } cout<<endl; } cout<<"命中率为:"<<(double)nm/(double)num<<endl; } void SLRU() { int p=0; int nm=0; for(int i=0;i<bnum;i++) { block[i].num=0; block[i].visited=false; } for(int i=0;i<num;i++) { int temp=Haven(page[i]); if(temp!=(-1)) { block[temp].visited=true; nm++; } else { for(int j=0;j<bnum;j++) { if(block[p].visited==false&&block[p].changed==false) { block[p].num=page[i]; if(rand()%2) { block[p].changed=true; } p=(++p)%bnum; goto over; } else { block[p].visited=false; p=(++p)%bnum; } } while(1) { if(block[p].changed==false) { block[p].num=page[i]; p=(++p)%bnum; break; } else { block[p].changed=false; p=(++p)%bnum; } } } over: for(int j=0;j<bnum;j++) { if(block[j].num!=0) { cout<<block[j].num<<" "; } } cout<<endl; } cout<<"命中率为:"<<(double)nm/(double)num<<endl; } ~Allocation(void) { } };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值