操作系统实验四

实验四: 页面置换

一、实验目的

设计和实现最佳置换算法、先进先出置换算法、最近最久未使用置换算法、改进型Clock置换算法、页面缓冲置换算法;通过页面访问序列随机发生器实现对上述算法的测试及性能比较。

二、实验环境

Windows 10 ,Visual Studio 2015

三、概要设计

1.数据结构

成员名

类型

作用

data

int

页号

flag

int

访问位

modify

int

修改位

根据各个算法的特点,程序实现的过程中用到的数据结构主要有以下三种:

  • 数组:定义的时候利用指针定义,然后根据全局变量block设定的给进程分配的物理内存的块数动态分配内存。一旦完成内存分配,不再改变数组的大小。

用到数组结构来实现的算法程序有:最佳置换算法,先进先出置换算法,最近最久未使用置换算法,改进型clock置换算法。

  • 队列:为单向队列,队列长度仍然由全局变量指定。

用到队列的算法程序有:先进先出置换算法。

队列结点元素的结构体如下:

typedef struct node

{

    int num;//页号

    node* next;//下一个结点页面

} Node, *pNode

typedef struct queue

{

    int n;//总的结点数

    pNode front;//队首指针

    pNode rear; //队尾指针

} Queue, *pQueue;

  • 链表:主要是将装入内存的页块串联起来。

用到链表的算法程序:页面缓冲算法。

链表结点元素的结构体如下:

struct LNode

{

    int data;//页号

    int flag;//访问位

    int modify;//修改位

    LNode* next;

};

struct Link

{

    int num;//当前链表上的结点数

    LNode* next;

};

2.模块和接口

  • 页面访问序列随机生成模块

在此模块中不事先传入参数,在模块开始时置入相关参数值(N,p,t等),再根据实验要求中的算法产生序列。

  • 算法接入模块

在本次实验中需实现五个算法。需要为这五个不同的算法传入参数,每个函数的返回值均为double类型的数值,代表对应的缺页率。

  • 测试模块

模拟页面置换过程,调用页面访问序列随机生成模块后再调用算法接入模块进行模拟,并打印缺页率。

3.算法实现

  • 页面访问序列随机生成算法

基本原理:

①确定虚拟内存的尺寸N,工作集的起始位置p,工作集中包含的页数e,工作集移动率m(每处理m个页面访问则将起始位置p +1),以及一个范围在0和1之间的值t;

②生成m个取值范围在p和p + e间的随机数,并记录到页面访问序列串中;

③生成一个随机数r,0 ≤ r ≤ 1;

④如果r < t,则为p生成一个新值,否则p = (p + 1) mod N;

⑤如果想继续加大页面访问序列串的长度,请返回第2步,否则结束。

流程图:

  • 最佳置换算法(OPT)

主要思想:

最佳置换算法的主要思想是,在发生页面替换时,被替换的对象应该满足,在以后的页面访问中,该对象不会再次被访问或者较晚被访问。是一种理想化算法,具有最好性能(对于固定分配页面方式,本法可保证获得最低的缺页率),但实际上却难于实现,故主要用于算法评价参照。

流程图:

  • 先进先出置换算法(FIFO)

主要思想:

在发生页面替换时,被替换的对象应该是最早进入内存的。

流程图:

  • 最近最久未使用置换算法(LRU)

主要思想:

在发生页面替换时,被替换的页面应该满足,在之前的访问队列中,该对象截止目前未被访问的时间最长。

流程图:

  • 改进型Clock置换算法

主要思想:

在每次页面替换时,总是尽可能地先替换掉既未被访问又未被修改的页面。

①从查寻指针当前位置起扫描内存分页循环队列,选择A=0且M=0的第一个页面淘汰;若未找到,转②

② 开始第二轮扫描,选择A=0且M=1的第一个页面淘汰,同时将经过的所有页面访问位置0;若不能找到,转①

流程图:

  • 页面缓冲算法(PBA)

主要思想:

设立空闲页面链表和已修改页面链表采用可变分配和基于先进先出的局部置换策略,并规定被淘汰页先不做物理移动,而是依据是否修改分别挂到空闲页面链表或已修改页面链表的末尾,空闲页面链表同时用于物理块分配,当已修改页面链表达到一定长度如Z个页面时,一起将所有已修改页面写回磁盘,故可显著减少磁盘I/O操作次数。

流程图:

4.主要函数功能说明  

(1)全局共享函数

void initMemo();//初始化存储空间,主要是设置分配空间的大小

void generate();//生成访问序列

bool isInMemo (int n); //指定页号是否已经在内存中

(2)最佳置换算法

void optimal (int n); //访问一个页面,执行一次最佳置换算法

void testOptimal();//算法实现函数

(3)先进先出置换算法

void initQueue (pQueue q);//初始化队列

void push (pQueue q, int num);//队列中加入新的页面结点

void pop (pQueue q);//将页面移出内存

void destroy (pQueue q);//销毁队列

bool findInQueue (pQueue q, int num);//查找页面是否已经调入内存

void generate();//生成访问序列

void fifoTest();//每访问一个页面,执行一次算法

void fifo (pQueue q, int num);//先进先出置换算法实现函数

(4)最近最久未使用置换算法

void LRU (int n);//每访问一个新的页面,执行一次LRU算法

void testLRU();//LRU算法实现函数

(5)改进型clock置换算法

void updated_Clock (int n);//改进型clock算法实现函数

void test_Clock();//每访问一个新的页面,执行一次算法

(6)页面缓冲算法

bool isInNodes (int n); //页面是否已经在链表中

void addToLink (int data, int type);//页面添加到已修改页面链表和空闲链表上

void emptyIdle();//将空闲链表上的所有页面送出内存

void emptyModi();//将已修改页面链表上所有的链表送出内存

void PBA (int n);//PBA算法实现函数

 

四、详细设计及测试结果

最佳置换、最近最久未使用、改进clock

// test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "stdio.h"
#include"stdlib.h"
#include"time.h"
#define R 32    //物理内存块数
#define V 64   //虚拟内存块数

struct LNode
{
    int data;
    int flag;//访问位
    int modify;//修改位
};

void initMemo();
void generate();//生成访问序列
bool isInMemo(int n); //
void optimal(int n); //
void testOptimal();
void LRU(int n);
void testLRU();
void updated_Clock(int n);
void test_Clock();


int block = 3;
int access[32]; //访问序列
int* memo;
int lost = 0;//没找到的页面数
int index = 0;//指示当前下标
LNode* nodes;//改进型Clock置换算法用到的数据结构

int _tmain(int argc, _TCHAR* argv[])
{
    generate();
    testOptimal();
    testLRU();
    test_Clock();
    int i = 0;
    for (; i < 32; i++)
    {
       printf("%d, ", access[i]);
    }
    getchar();
    getchar();
    return 0;
}

void generate()
{
    srand((unsigned)time(NULL)); //用时间做种,每次产生随机数不一样
    int p = rand() % 64;
    int m = 8, e = 8;
    int i, j;
    double t;
    t = rand() % 10 / 10.0;
    for (i = 0; i < 4; i++)
    {
       for (j = i * m; j < (i + 1) *m; j++)
       {
           access[j] = (p + rand() % e) % 64;
       }
       double r = (rand() % 10) / 10.0;
       if (r < t)
       {
           p = rand() % 64;
       }
       else
       {
           p = (p + 1) % 64;
       }
    }
}

void initMemo()
{
    memo = (int*)malloc(block * sizeof(int));
    int i = 0;
    for (; i < block; i++)
    {
       memo[i] = -1;
    }
    return;
}

void testOptimal()
{
    initMemo();
    int i = 0;
    printf("最佳置换算法:\n");
    for (; i < 32; i++)
    {
       optimal(i);
       printf("%d %d %d\n", memo[0], memo[1], memo[2]);
    }
    printf("最佳置换算法缺页率: %2f %d\n", lost / 32.0, lost);
    lost = 0;
    free(memo);
    index = 0;
}

bool  isInMemo(int n)
{
    int i = 0;
    for (; i < block; i++)
    {
       if (access[n] == memo[i])
       {
           return true;
       }
    }
    return false;
}

//最佳适应算法
void optimal(int n)
{
    int i = 0, j = 0;
    if (isInMemo(n))
    {
       printf("页面已被调入内存\n");
    }
    else
       if (index == block)
       {
           lost++;
           int max = 0, pos, tag;
           for (i = 0; i < block; i++)
           {
              tag = -1;
              for (j = n + 1; j < 32; j++)
              {
                  if (access[j] == memo[i])
                  {
                     tag = j;
                     break;
                  }
              }
              if (tag == -1)
              {
                  max = 32;
                  pos = i;
                  break;
              }
              else
              {
                  if (max < tag)
                  {
                     max = tag;
                     pos = i;
                  }
              }
           }
           memo[pos] = access[n];
       }
       else
       {
           memo[index] = access[n];
           index++;
       }
}

LRU算法
void LRU(int n)
{
    int i, j;
    if (isInMemo(n))
    {
       printf("页面已被调入内存\n");
    }
    else
       if (index == block)
       {
           int max = n, pos = -1, tag;
           for (i = 0; i < block; i++)
           {
              for (j = n - 1; j >= 0; j--)
              {
                  if (access[j] == memo[i])
                  {
                     tag = j;
                     break;
                  }
              }
              if (tag < max)
              {
                  max = tag;
                  pos = i;
                  if (max == 0)
                  {
                     break;
                  }
              }
           }
           memo[pos] = access[n];
           lost++;
       }
       else
       {
           memo[index] = access[n];
           index++;
       }
}

void testLRU()
{
    int i;
    initMemo();
    printf("最近最久未使用算法\n");
    for (i = 0; i < 32; i++)
    {
       LRU(i);
       printf("%d %d %d\n", memo[0], memo[1], memo[2]);
    }
    printf("最近最久未使用缺页率: %2f %d \n", lost / 32.0, lost);
    lost = 0;
    index = 0;
    free(memo);
}

bool isInNodes(int n)
{
    int i;
    for (i = 0; i < block; i++)
    {
       if (nodes[i].data == access[n])
       {
           return true;
       }
    }
    return false;
}


void updated_Clock(int n)
{
    if (isInNodes(n))
    {
       printf("页面已被调入内存\n");
    }
    else
       if (index == block)
       {
           lost++;
           int i = 0, tag = -1;
           while (true)
           {
              if ((i / block) % 2 == 0)
              {
                  if (nodes[i % block].flag == 0 && nodes[i % block].modify == 0)
                  {
                      tag = i % block;
                      break;
                  }
              }
              if ((i / block) % 2 == 1)
              {
                  if (nodes[i % block].flag == 0 && nodes[i % block].modify == 1)
                  {
                     tag = i % block;
                     break;
                  }
                  else
                  {
                     nodes[i % block].flag = 0;
                  }
              }
              i++;
           }
           nodes[tag].data = access[n];
           nodes[tag].flag = 1;
           if (rand() % 10 < 4)
           {
              nodes[tag].modify = 1;
           }
           else
           {
              nodes[tag].modify = 0;
           }
       }
       else
       {
           nodes[index].data = access[n];
           nodes[index].flag = 1;
           if (rand() % 10 < 4)
           {
              nodes[index].modify = 1;
           }
           else
           {
              nodes[index].modify = 0;
           }
           index++;
       }
}

void test_Clock()
{
    int i = 0, j = 0;
    printf("改进型Clock置换算法\n");
    nodes = (LNode*)malloc(block * sizeof(LNode));
    for (i = 0; i < block; i++)
    {
       nodes[i].data = -1;
       nodes[i].flag = -1;
       nodes[i].modify = -1;
    }
    for (i = 0; i < 32; i++)
    {
       updated_Clock(i);
       for (j = 0; j < block; j++)
       {
           printf("%d ", nodes[j].data);
       }
       printf("\n");
    }
    printf("改进型Clock置换算法缺页率: %2f %d \n", lost / 32.0, lost);
    lost = 0;
    index = 0;
}

先进先出

// FIFO.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "time.h"

typedef struct node
{
    int num;
    node* next;
} Node, *pNode;

typedef struct queue
{
    int n;
    pNode front;
    pNode rear;
} Queue, *pQueue;


void initQueue(pQueue q);
void push(pQueue q, int num);
void pop(pQueue q);
void destroy(pQueue q);
bool findInQueue(pQueue q, int num);
void generate();
void fifoTest();
void fifo(pQueue q, int num);
int access[32];//访问序列
int size = 3;//给进程分配的内存的大小
int lost = 0;//缺页数

int _tmain(int argc, _TCHAR* argv[])
{
    generate();
    fifoTest();
    getchar();
    getchar();
    return 0;
}

void initQueue(pQueue q)
{
    q->rear = (pNode)malloc(sizeof(Node));
    if (q->rear == NULL)
    {
        printf("failed\n");
    }
    else
    {
        q->front = q->rear;
        q->rear->next = NULL;
        q->front->next = NULL;
        q->n = 0;
    }
}

void push(pQueue q, int num)
{
    pNode p = (pNode)malloc(sizeof(Node));
    if (p == NULL)
    {
        printf("failed");
    }
    else
    {
        p->next = NULL;
        p->num = num;
        if (q->front == q->rear)
        {
            q->front->next = p;
            q->rear = p;
        }
        else
        {
            q->rear->next = p;
            q->rear = p;
        }
        q->n++;
    }
}

void pop(pQueue q)
{
    pNode p;
    if (q->front != q->rear)
    {
        p = q->front->next;
        q->front->next = p->next;
        if (p == q->rear)
        {
            q->front = q->rear;
        }
        q->n--;
        free(p);
    }
}

void destroy(pQueue q)
{
    while (q->front != q->rear)
    {
        pop(q);
    }
}

bool findInQueue(pQueue q, int num)
{
    pNode p;
    if (q->front != q->rear)
    {
        p = q->front->next;
        while (p)
        {
            if (p->num == num)
            {
                return true;
            }
            else
            {
                p = p->next;
            }
        }
    }
    return false;
}

/*
生成具有局部访问特点的访问序列
*/
void generate()
{
    srand((unsigned)time(NULL)); //用时间做种,每次产生随机数不一样
    int p = rand() % 64;
    int m = 8, e = 8;
    int i, j;
    double t;
    t = rand() % 10 / 10.0;
    for (i = 0; i < 4; i++)
    {
        for (j = i * m; j < (i + 1) *m; j++)
        {
            access[j] = (p + rand() % e) % 64;
        }
        double r = (rand() % 10) / 10.0;
        if (r < t)
        {
            p = rand() % 64;
        }
        else
        {
            p = (p + 1) % 64;
        }
    }
}

void fifoTest()
{
    Queue q;
    pNode p;
    initQueue(&q);
    int i = 0;
    printf("先进先出置换算法\n");
    for (; i < 32; i++)
    {
        fifo(&q, access[i]);
        p = q.front->next;
        while (p)
        {
            printf("%d ", p->num);
            p = p->next;
        }
        printf("\n");
    }
    printf("先进先出算法缺页率:%f  %d\n", lost / 32.0, lost);
    destroy(&q);
}

void fifo(pQueue q, int num)
{
    if (findInQueue(q, num))
    {
        printf("页面已调入内存\n");
    }
    else
    {
        if (q->n == size)
        {
            pop(q);
            push(q, num);
            lost++;
        }
        else
        {
            push(q, num);
        }
    }
}



页面缓冲

// PBA.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "stdio.h"
#include"stdlib.h"
#include"time.h"
#define M 32    //物理内存块数
#define N 64   //虚拟内存块数

struct LNode
{
    int data;
    int flag;//访问位
    int modify;//修改位
    LNode* next;
};
struct Link
{
    int num;//当前链表上的结点数
    LNode* next;
};

void generate();//生成访问序列
bool isInNodes(int n); //
void addToLink(int data, int type);
void emptyIdle();
void emptyModi();
void PBA(int n);
int size = 3;
int p;//工作集的起始位置
int table[32];//物理内存,每一个元素代表一个页面
int access[32]; //访问序列
int memo[3] = { -1, -1, -1 };
int lost = 0;//没找到的页面数
int index = 0;//指示当前下标
LNode* nodes;//改进型Clock置换算法用到的数据结构
Link idle;
Link modified;

int _tmain(int argc, _TCHAR* argv[])
{
    int i = 0, j = 0;
    generate();
    printf("页面缓冲置换算法(PBA)\n");
    idle.num = 0;
    idle.next = NULL;
    modified.num = 0;
    modified.next = NULL;
    nodes = (LNode*)malloc(size * sizeof(LNode));
    for (i = 0; i < size; i++)
    {
        nodes[i].data = -1;
        nodes[i].flag = 0;
        nodes[i].modify = 0;
        nodes[i].next = NULL;
    }
    for (i = 0; i < 32; i++)
    {
        PBA(i);
        for (j = 0; j < size; j++)
        {
            printf("%d ", nodes[j].data);
        }
        printf("\n");
    }
    printf("页面缓冲置换算法(PBA)缺页率:%f   %d\n", lost / 32.0, lost);
    getchar();
    getchar();
    return 0;
}

void generate()
{
    srand((unsigned)time(NULL)); //用时间做种,每次产生随机数不一样
    p = rand() % 64;
    int m = 8, e = 8;
    int i, j;
    double t;
    t = rand() % 10 / 10.0;
    for (i = 0; i < 4; i++)
    {
        for (j = i * m; j < (i + 1) *m; j++)
        {
            access[j] = (p + rand() % e) % 64;
        }
        double r = (rand() % 10) / 10.0;
        if (r < t)
        {
            p = rand() % 64;
        }
        else
        {
            p = (p + 1) % 64;
        }
    }
}

bool isInNodes(int n)
{
    int i;
    for (i = 0; i < 3; i++)
    {
        if (nodes[i].data == access[n])
        {
            return true;
        }
    }
    return false;
}

LNode* isinLinks(int n)
{
    LNode*p, *q;
    p = idle.next;
    q = NULL;
    while (p)
    {
        if (p->data == access[n])
        {
            if (q != NULL)
            {
                q->next = p->next;
                p->next = NULL;
                idle.num--;
                break;
            }
            else
            {
                idle.next = NULL;
            }
        }
        q = p;
        p = p->next;
    }
    if (p == NULL)
    {
        p = modified.next;
        while (p != NULL)
        {
            if (p->data == access[n])
            {
                if (p == modified.next)
                {
                   modified.next = p->next;
                }
                else
                {
                   q->next = p->next;
                   p->next = NULL;
                   modified.num--;
                }
                if (modified.num == 0)
                {
                   modified.next = NULL;
                }
                break;
            }
            q = p;
            p = p->next;
        }
    }
    return p;
}

void PBA(int n)
{
    if (isInNodes(n))
    {
        printf("已装入内存\n");
    }
    else
        if (index == size)
        {
            LNode *p;
            if ((p = isinLinks(n)) != NULL)
            {
                nodes = (LNode*)realloc(nodes, (size + 1) * sizeof(LNode));
                nodes[size].data = p->data;
                nodes[size].flag = p->flag;
                nodes[size].modify = p->modify;
                nodes[size].next = p->next;
                free(p);
                size++;
                index++;
            }
            else
            {
                lost++;//缺页
                if (nodes[n % 3].modify == 1)
                {
                   addToLink(nodes[n % 3].data, 1);
                }
                else
                {
                   addToLink(nodes[n % 3].data, 0);
                }
                nodes[n % 3].data = access[n];
                nodes[n % 3].flag = 1;
                nodes[n % 3].next = NULL;
                if (rand() % 10 < 4)
                {
                   nodes[n % 3].modify = 0;
                }
                else
                {
                   nodes[n % 3].modify = 1;
                }
            }
        }
        else
        {
            nodes[index].data = access[n];
            nodes[index].flag = 1;
            nodes[index].next = NULL;
            if (rand() % 10 < 4)
            {
                nodes[index].modify = 1;
            }
            else
            {
                nodes[index].modify = 0;
            }
            index++;
        }
}

void addToLink(int data, int type)
{
    LNode* p;
    LNode* q;
    q = (LNode*)malloc(sizeof(LNode));
    q->data = data;
    q->flag = 1;
    if (type == 1)
    {
        q->modify = 1;
        p = modified.next;
    }
    else
    {
        q->modify = 0;
        p = idle.next;
    }
    q->next = NULL;
    if (p == NULL)
    {
        if (type == 0)
        {
            idle.next = q;
        }
        else
        {
            modified.next = q;
        }
    }
    else
    {
        while (p)
        {
            if (p->next == NULL)
            {
                p->next = q;
                break;
            }
            else
            {
                p = p->next;
            }
        }
    }
    if (type == 0)
    {
        idle.num += 1;
        if (idle.num == 10)
        {
            emptyIdle();
        }
    }
    else
    {
        modified.num += 1;
        if (modified.num == 10)
        {
            emptyModi();
        }
    }
}

void emptyIdle()
{
    LNode* p;
    p = idle.next;
    while (p)
    {
        idle.next = p->next;
        free(p);
        p = idle.next;
    }
    idle.num = 0;
}

void emptyModi()
{
    LNode* p;
    p = modified.next;
    while (p)
    {
        modified.next = p->next;
        free(p);
        p = modified.next;
    }
    modified.num = 0;
}

随机生成的页面序列为17, 23, 17, 18, 23, 20, 19, 18, 21, 22, 17, 21, 23, 18, 21, 20, 22, 23, 19, 21, 20, 25, 25, 25, 26, 22, 26, 22, 23, 20, 24, 21

最佳置换:

先进先出:

最近最久未使用:

改进型clock:

页面缓冲:

内存空间块数为3

置换算法

最佳置换算法

先进先出置换算法

最近最久未使用算法

改进型clock置换算法

页面缓冲置换算法

测试序列1

缺页数

15

21

21

21

13

缺页率

0.468750

0.656250

0.656250

0.656250

0.406250

测试序列2

缺页数

20

23

22

21

20

缺页率

0.625000

0.718750

0.687500

0.656250

0.625000

测试序列3

缺页数

16

23

24

22

13

缺页率

0.500000

0.718750

0.750000

0.687500

0.406250

内存空间块数为5

置换算法

最佳置换算法

先进先出置换算法

最近最久未使用算法

改进型clock置换算法

页面缓冲置换算法

测试序列1

缺页数

13

15

15

15

14

缺页率

0.406250

0.468750

0.468750

0.468750

0.437500

测试序列2

缺页数

11

15

14

14

14

缺页率

0.343750

0.468750

0.437500

0.437500

0.437500

测试序列3

缺页数

9

11

10

12

12

缺页率

0.281250

0.343750

0.312500

0.375000

0.375000

根据上述结果,可以得出结论:

①同一种算法,对于不同的访问序列,其缺页率是不同,会有所变化。

②总的来看,最佳置换算法的缺页率是最低的。剩下的集中算法中,页面缓冲算法的缺页率要低于其他置换算法。改进型clock算法稍微好于先进先出算法和最近最久未使用算法。先进先出算法和最近最久未使用算法性能相近。总的来看,性能(缺页率)如下。

最佳置换算法>页面缓冲置换算法>改进型clock置换算法>最近最久未使用算法>=先进先出置换算法。

③对比内存块数和内存块数为5两种情况下的同一序列下的同一算法,可以发现,算法的缺页率还跟分配的内存块数有关系,分配的内存块数越多,缺页率越低。即导入内存的块数越多,发生缺页的可能性就越小。

 

 

GitHub源码:https://github.com/wwyw/lab4

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值