操作系统 页面置换算法模拟

据实验作业挑选了几种页面置换算法进行实验.(仅个人理解

1.先进先出页面置换算法(FIFO).
2.最近最久未被使用页面置换算法(LRU).
3.最佳页面置换算法(OPT).
4.最少使用页面置换算法(LFU). [有时间再补充.
5.Clock页面置换算法. [有时间再补充.

对着书上的一个样例来写的, 因为书上的样例都是页面编号为(0~7), 所以绝大部分存储对应编号页面信息的数组都是开的为8的大小. 需求动态需要自己理解并且修改.


一.  首先是 先进先出页面置换算法(FIFO). 每次需要置换时都会淘汰最先进入内存的页面. 如若这样解释,我们是不能换种说法 – 每次需要置换时都删除队头元素, 然后在队尾添加一个新的元素? 所以这就是一个队列 queue 操作. 当然如果不需要置换时, 也就是页面存储含所需页面时, 就不进行出队入队操作. C++中是有封装 queue 队列的, 所以使用内置库我们可以很快得到代码.

#include<bits/stdc++.h>
using namespace std;
int len, nums, sum, hand;
void PrintQueue(queue<int> q){
    int cnt = len - q.size();
    cout << ' ' << nums << ":";
    while (!q.empty()){
        cout << ' ' << q.front();
        q.pop();
    }
    while(cnt --) cout << ' ' << '_';
    cout << endl;
}
signed main(void){
    freopen("in.txt","r",stdin);//3 7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1
    freopen("out.txt","w",stdout);
    queue<int>que;
    map<int , bool>ma; //用来标记是否在页面存储块中.
    cout << " input Total number of pages:" << endl;
    cin >> len; cout << " pages:" << len << endl;
    cout << " input this round is the page to be used:" << endl;
    while(cin >> nums){
        if(ma[nums]) cout << ' ' << nums << ": not do, the pag is in it" << endl;
        if(!ma[nums] && que.size() == len) ma[que.front()] = false , que.pop() , hand ++;
        if(!ma[nums]) ma[nums] = true , que.emplace(nums) , PrintQueue(que) , sum ++;
        cout << endl;
        cout << " input this round is the page to be used:" << endl;
    }cout << ' ' << hand << ' ' << sum << endl;
    return 0;
}

  上面我们这样写虽然可以没次都准确的得到页面存储块中存储的页面号, 但是并没有对 “地址” 这一概念进行实现. 就是没有很好的模拟页面存储的逻辑地址. 为了能对逻辑地址进行模拟, 我们修改一下映射方法. 也就是让 map 不再是直接存储是否存在页面存储块中, 而是直接存储在存储块的哪个位置. 上面这段代码的运行结果就不给出了.

#include<bits/stdc++.h>
using namespace std;
int len, nums, sum, hand, ide = 1;
void Print(vector<int> vec){
    int i;
    for(i = 1;i <= len;i ++){
        if(vec[i] == -1) break;
        cout << ' ' << vec[i];
    }
    while(i <= len){
        cout << " _"; 
        i ++;
    }cout << endl;
}
signed main(void){
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    queue<int>que;
    map<int , int>ma;
    cout << " input Total number of pages:" << endl;
    cin >> len; cout << " pages:" << len << endl;
    vector<int>vec(len+1 , -1);
    cout << " input this round is the page to be used:" << endl;
    while(cin >> nums){
        cout << " " << nums << ": ";
        if(ma[nums]){ //当页面存储块存在需求页面
            cout << "do not, the pag is in it" << endl;
            cout << endl;
            cout << " input this round is the page to be used:" << endl;
            continue;
        }

        if(ide <= len){ //虽然这样写有些麻烦,但是方便理解.存储块1~len.
            ma[nums] = ide;
            vec[ide ++] = nums; 
            que.emplace(nums);
            sum ++;
        }else if(!ma[nums]){
            //出存储操作(去除队头元素, 记录页面内存块中的位置, 将出队的页面映射置零.
            int num = que.front(); que.pop(); int index = ma[num]; ma[num] = 0; 
            
            //进存储操作(新页面入队, 建立元素的映射, 修改内存块页面存储.
            que.emplace(nums), ma[nums] =  index, vec[index] = nums;

            //hand记录置换的次数, sum记录一共判断的页面数.
            hand ++, sum ++;
        }
        Print(vec);

        cout << endl;
        cout << " input this round is the page to be used:" << endl;
    }cout << ' ' << hand << ' ' << sum << endl;
    return 0;
}

  这样我们的输出就和书上的一样了. 上面这段代码有些地方是可以合并优化的, 但是为了更好的理解和阅读, 我进行了分割 (一步一步的递进. 该段代码的运行结果为:

 input Total number of pages:
 pages:3
 input this round is the page to be used:
 7:  7 _ _

 input this round is the page to be used:
 0:  7 0 _

 input this round is the page to be used:
 1:  7 0 1

 input this round is the page to be used:
 2:  2 0 1

 input this round is the page to be used:
 0: do not, the pag is in it

 input this round is the page to be used:
 3:  2 3 1

 input this round is the page to be used:
 0:  2 3 0

 input this round is the page to be used:
 4:  4 3 0

 input this round is the page to be used:
 2:  4 2 0

 input this round is the page to be used:
 3:  4 2 3

 input this round is the page to be used:
 0:  0 2 3

 input this round is the page to be used:
 3: do not, the pag is in it

 input this round is the page to be used:
 2: do not, the pag is in it

 input this round is the page to be used:
 1:  0 1 3

 input this round is the page to be used:
 2:  0 1 2

 input this round is the page to be used:
 0: do not, the pag is in it

 input this round is the page to be used:
 1: do not, the pag is in it

 input this round is the page to be used:
 7:  7 1 2

 input this round is the page to be used:
 0:  7 0 2

 input this round is the page to be used:
 1:  7 0 1

 input this round is the page to be used:
 12 15


二.  最近最久未使用页面置换算法(LRU) 和先进先出页面置换算法(FIFO)其实很像. 我们已经写完了先进先出的概念. 其中我们在先进先出算法中对页面存储块有我们所需页面时, 是不进行操作的. 这就是和LRD 的不同点. 在 LRD 算法遇到页面已经在页面存储块中时, 需要把该页面放到队尾. (虽然需要我们使用栈的思想, 但是 queue 是只读属性. 所以最好还是用 vector 来模拟.
  寄存器: R = R n − 1 R n − 2 . . . R 0 R= R_{n-1}R_{n-2}...R_0 R=Rn1Rn2...R0. 每隔一段时间就右移一个单位. 因为我们无法模拟内存的内存置换的 “时间” 这一概念, 所以我们就每需要判断一次页面就右移一次.
  如果不是强加寄存器这一概念的话, 其实用整型变量来记录时间戳反而能更直观的模拟实验.

#include<bits/stdc++.h>
using namespace std;
struct pages{
    int val;
    int index; //物理地址
    bitset<8>bit;
    bool operator < (const struct pages &a) const { //重载排序
        string op = bit.to_string();
        string stra = a.bit.to_string();
        return (op<stra?true:false);
    }
};
struct pages page[8]; //因为样例是一共8个页面(0~7),所以这里就不设置动态了
int len, nums;
vector<struct pages>p_que; //vector模拟队列
void Print(vector<int> vec){
    int i;
    for(i = 1;i <= len;i ++){
        if(vec[i] == -1) break;
        cout << ' ' << vec[i];
    }
    while(i <= len){
        cout << " _"; i ++;
    }cout << endl;
}
void debug(vector<struct pages> p_que){
    for(int i = 0;i < p_que.size();i ++){
        cout << p_que[i].bit << ":" << p_que[i].val << " ";
    }
    cout << endl << endl;
}
signed main(void){
    freopen("in.txt","r",stdin);//3 7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1
    freopen("LRUout.txt","w",stdout);
    cout << " input Total number of pages:" << endl;
    cin >> len; cout << " pages:" << len << endl;
    vector<int>vec(len + 1 , -1); //模拟实际存储状况
    map<int , bool>ma;
    for(int i = 0;i < 8;i ++) page[i].val = i;
    cout << " input this round is the page to be used:" << endl;
    while(cin >> nums){
        cout << ' ' << nums << ": ";
        //每一个计数器都右移
        for(int i = 0;i < 8;i ++) page[i].bit >>= 1;
        //当前需要的页面最高位置为1
        page[nums].bit[7] = 1;

        //页面块没有满的操作(构成逻辑存储位置和优先队列的映射关系
        if(p_que.size() < len){ 
            vec[p_que.size() + 1] = nums; //对存储情况进行修改
            page[nums].index = p_que.size() + 1; //添加优先度与索引
            p_que.emplace_back(page[nums]); //进入模拟队列
        }else if(!ma[nums]) { //满了后,优先队列的修改,逻辑存储块的映射修改 
            vec[p_que[0].index] = nums; //修改模拟存储状况
            ma[p_que[0].val] = false; //取消出队标记
            page[nums].index = p_que[0].index; //修改页面信息
            p_que[0] = page[nums]; //修改模拟队列
        }
        //标记这个页面一定在存储块中, 不放在前面的原因是, 写在才真正放进去了
        ma[nums] = true;

        for(int i = 0;i < p_que.size();i ++) p_que[i] = page[p_que[i].val];
        sort(p_que.begin() , p_que.end());
        Print(vec);
        debug(p_que);
    }
    return 0;
}

   p s : ps: ps:需要动态则将结构体内的 " b i t s e t " "bitset" "bitset" 大小, 还有 s t r u c t struct struct p a g e s pages pages定义的结构体数组大小修改为最大页面编号. (你往大了设置就好了.
写的很复杂, 因为我们这里偷换了概念, 将一段时间内右移改成了每来一个页面右移动一次. 所以为了切合这种思想, 我还是对 bitset 排了序. 运行结果为:

 input Total number of pages:
 pages:3
 input this round is the page to be used:
 7:  7 _ _
10000000:7 

 0:  7 0 _
01000000:7 10000000:0 

 1:  7 0 1
00100000:7 01000000:0 10000000:1 

 2:  2 0 1
00100000:0 01000000:1 10000000:2 

 0:  2 0 1
00100000:1 01000000:2 10010000:0 

 3:  2 0 3
00100000:2 01001000:0 10000000:3 

 0:  2 0 3
00010000:2 01000000:3 10100100:0 

 4:  4 0 3
00100000:3 01010010:0 10000000:4 

 2:  4 0 2
00101001:0 01000000:4 10000100:2 

 3:  4 3 2
00100000:4 01000010:2 10001000:3 

 0:  0 3 2
00100001:2 01000100:3 10001010:0 

 3:  0 3 2
00010000:2 01000101:0 10100010:3 

 2:  0 3 2
00100010:0 01010001:3 10001000:2 

 1:  1 3 2
00101000:3 01000100:2 10000000:1 

 2:  1 3 2
00010100:3 01000000:1 10100010:2 

 0:  1 0 2
00100000:1 01010001:2 10000100:0 

 1:  1 0 2
00101000:2 01000010:0 10010000:1 

 7:  1 0 7
00100001:0 01001000:1 10000000:7 

 0:  1 0 7
00100100:1 01000000:7 10010000:0 

 1:  1 0 7
00100000:7 01001000:0 10010010:1 

三. 最佳页面置换算法(OPT). 该页面置换算法置换出去的页面都是在未来最长时间不被使用的页面. 因为我们要对未来的页面进行检索, 所以使用该页面算法有一个默认的条件就是, 我们必须一开始知道完整的页面需求列表.

#include<bits/stdc++.h>
using namespace std;
int len, nums, maxn;
//如果有更多的页,或者不确定多少页(需要输入), 那么8改成一共的页数. 
vector<int>inde; //这里设置大小为8是因为样例只有8个页面.存储各个页面离当前位子最近的下标
vector<int>pages; //存储页面进入顺序
vector<map<int , int>>vec; //一次进入页面和其他页面的距离
void debug(){
    for(int i = 0;i < vec.size();i ++){
        cout << pages[pages.size() - i - 1] << ": ";
        for(int j = 0;j < maxn;j ++){
            cout << vec[i][j] << ' ';
        }cout << endl;
    }
}
void Pretreatment(){ //预处理
    vector<int>no(maxn , INT_MAX);
    inde = no;
    for(int i = pages.size() - 1;i >= 0;i --){
        inde[pages[i]] = i;
        map<int , int>pu;
        for(int j = 0;j < maxn;j ++){  //这里的8也是可变的
            if(inde[j] == INT_MAX) pu[j] = INT_MAX;
            else pu[j] = inde[j] - i;
        }
        vec.emplace_back(pu);
    }
}
void Work(){
    int ide = 0;
    vector<int>page; //页面存储
    map<int , bool>ma; //标记页面存储块中的存储情况.
    while(page.size() < len){ 
        cout << ' ' << pages[ide] << ": ";
        page.emplace_back(pages[ide]), ma[pages[ide]]= true, ide ++;
        int i;
        for(i = 0;i < page.size();i ++) cout << ' ' << page[i];
        while(i < len) {cout << " _"; i ++;}
        cout << endl << endl;
    }
    while(ide < pages.size()){
        cout << ' ' << pages[ide] << ": ";
        if(ma[pages[ide]]){
            cout << " do not, this page is in it" << endl;
        }else{
            int cnt = 0;
            // cout << vec[ide][page[0]] << ' ';
            for(int i = 1;i < len;i ++){
                // cout << vec[ide][page[i]] << ' ';
                cnt = (vec[pages.size() - ide - 1][page[i]]>vec[pages.size() - ide - 1][page[cnt]]?i:cnt);
            }
            // cout << " *" << cnt << "* ";
            ma[page[cnt]] = false , ma[pages[ide]] = true;
            page[cnt] = pages[ide];
            for(auto ao : page) cout << ' ' << ao;
            cout << endl;
        }

        cout << endl;
        ide ++;
    }
}
signed main(void){
    freopen("in.txt","r",stdin);//3 8 7 0 1 2 0 3 0 4 2 3 0 3 2 1 2 0 1 7 0 1
    freopen("OPTout.txt","w",stdout);
    cout << " input Total number of pages:" << endl;
    cin >> len; cout << " pages:" << len << endl;
    cout << " the length of pages:" << endl;
    cin >> maxn; cout << " maxn:" << maxn << endl;
    while(cin >> nums) pages.emplace_back(nums);
    Pretreatment();
    Work();
    // debug();
    return 0;
}

  设置了动态的, 你需要优先输入你的 页面存储块大小(最大页面编号+1). [下标从0开始.
  你可以每到需要置换页面时候就往后查询, 寻找符合要求的页面. 但是预处理+哈希能够减少复杂程度. (写预处理+哈希容易出错, 其实不在要求时间复杂度的情况下, 直接往后查询更加的直观, 也更加容易完成. 运行结果如下:

  input Total number of pages:
 pages:3
 the length of pages:
 maxn:8
 7:  7 _ _

 0:  7 0 _

 1:  7 0 1

 2:  2 0 1

 0:  do not, this page is in it

 3:  2 0 3

 0:  do not, this page is in it

 4:  2 4 3

 2:  do not, this page is in it

 3:  do not, this page is in it

 0:  2 0 3

 3:  do not, this page is in it

 2:  do not, this page is in it

 1:  2 0 1

 2:  do not, this page is in it

 0:  do not, this page is in it

 1:  do not, this page is in it

 7:  7 0 1

 0:  do not, this page is in it

 1:  do not, this page is in it

只是模拟, 实际上与计算机本来的存储不一样

--over

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值