最近最久未使用(LRU)頁面置換演算法 C語言實現

HowfunLin發表於2020-12-15

廣東工業大學 作業系統實驗

實驗內容

假設每個頁面中可存放10條指令,分配給作業的記憶體塊數為4。用C語言模擬一個作業的執行過程,該作業共有320條指令,即它的地址空間為32頁,目前它的所有頁都還未調入記憶體。在模擬過程中,如果所訪問的指令已在記憶體,則顯示其實體地址,並轉下一條指令。如果所訪問的指令還未裝入記憶體,則發生缺頁,此時需記錄缺頁的次數,並將相應頁調入記憶體。如果4個記憶體塊均已裝入該作業,則需進行頁面置換,最後顯示其實體地址,並轉下一條指令。在所有320指令執行完畢後,請計算並顯示作業執行過程中發生的缺頁率。

置換演算法:採用最近最久未使用(LRU)頁面置換演算法。

通過隨機數產生一個指令序列,共320條指令:
1)指令的地址按下述原則生成:
① 50%的指令是順序執行的;
② 25%的指令是均勻分佈在前地址部分;
③ 25%的指令是均勻分佈在後地址部分;
具體的實施方法是:
① 在[0,319]的指令地址之間隨機選取一起點m;
② 順序執行一條指令,即執行序號為m+1的指令;
③ 在前地址[0,m-1]中隨機選取一條指令並執行,該指令的序號為m1;
④ 順序執行一條指令,其序號為m1+1的指令;
⑤ 在後地址[m1+2,319]中隨機選取一條指令並執行,該指令的序號為m2;
⑥ 順序執行一條指令,其序號為m2+1的指令;
重複上述步驟①~⑥,直到執行320次指令。
2)將指令序列變換為頁地址流
設頁面大小為1K, 使用者虛存容量為32K。在使用者虛存中,按每K存放10條指令排列虛存地址,即320條指令在虛存中的存放方式為:
第0條~第9條指令為第0頁(對應虛存地址為[0,9]);
第10條~第19條指令為第1頁(對應虛存地址為[10,19]);
……
……
第310條~第319條指令為第31頁(對應虛存地址為[310,319])。
按以上方式,使用者指令可組成32頁。

程式碼實現

#include <stdio.h>
#include <stdlib.h>

float count = 0; //缺頁次數
int instrAddr[320]; //指令地址流陣列
int pageAddr[320]; //頁地址流陣列

typedef struct Data //資料域
{
    int pageNum; //裝進的使用者虛存頁號
    int blockNum; //塊號
    int t; //自上次被訪問以來所經歷的時間
} Data;

typedef struct BlockNode //單向迴圈連結串列
{
    Data data;
    struct BlockNode *next;
} Block, *BlockList;

//定義記憶體塊
BlockList block1;
BlockList block2;
BlockList block3;
BlockList block4;

void initialize() //初始化
{
    block1 = (BlockList)malloc(sizeof(Block));
    block2 = (BlockList)malloc(sizeof(Block));
    block3 = (BlockList)malloc(sizeof(Block));
    block4 = (BlockList)malloc(sizeof(Block));

    block1->data.pageNum = -1;
    block2->data.pageNum = -1;
    block3->data.pageNum = -1;
    block4->data.pageNum = -1;

    block1->data.blockNum = 0;
    block2->data.blockNum = 1;
    block3->data.blockNum = 2;
    block4->data.blockNum = 3;

    block1->data.t = 0;
    block2->data.t = 0;
    block3->data.t = 0;
    block4->data.t = 0;

    block1->next = block2;
    block2->next = block3;
    block3->next = block4;
    block4->next = block1;

    for(int i = 0; i < 320; ) //初始化地址流
    {
        int m = rand() % 320;
        instrAddr[i] = m + 1;
        pageAddr[i] = instrAddr[i] / 10;
        i++;

        int m1 = rand() % (m - 1);
        instrAddr[i] = m1;
        pageAddr[i] = m1 / 10;
        i++;

        instrAddr[i] = m1 + 1;
        pageAddr[i] = instrAddr[i] / 10;
        i++;

        int m2 = rand() % (319 - m1 - 1) + m1 + 2;
        instrAddr[i] = m2;
        pageAddr[i] = m2 / 10;
        i++;

        instrAddr[i] = m2 + 1;
        pageAddr[i] = instrAddr[i] / 10;
        i++;
    }
}

int LRU(int pageNum, int virAddr)
{
    Block *p = block1;

    for(int i = 0; i < 4; i++) //遍歷所有記憶體塊,若不進行任何操作則遍歷結束時候仍指向block1
    {
        if(p->data.pageNum == -1) //塊為空閒
        {
            p->data.pageNum = pageNum;
            count++; //缺頁次數+1
            printf("指令地址:%d \n", virAddr);
            printf("指令未裝入記憶體!頁面置換完成!\n使用者指令第%d頁第%d條的實體地址為:第%d塊第%d條 \n\n", pageNum, (virAddr % 10), p->data.blockNum, (virAddr % 10));

            //將所有塊經歷的時間+1,再將當前訪問塊的時間置0
            for(int i = 0; i < 4; i++)
            {
                p->data.t++;
                p = p->next;
            }

            p->data.t = 0;

            return 1;
        }

        if(p->data.pageNum == pageNum)
        {
            printf("指令地址:%d \n", virAddr);
            printf("指令已在記憶體中!\n使用者指令第%d頁第%d條的實體地址為:第%d塊第%d條 \n\n", pageNum, (virAddr % 10), p->data.blockNum, (virAddr % 10));

            for(int i = 0; i < 4; i++)
            {
                p->data.t++;
                p = p->next;
            }

            p->data.t = 0;

            return 1;
        }

        p = p->next;
    }

    //頁面置換
    int largestT = -1;

    for(int i = 0; i < 4; i++) //
    {
        if(p->data.t > largestT)
        {
            largestT = p->data.t;
        }

        p = p->next;
    }

    for(int i = 0; i < 4; i++)
    {
        if(p->data.t == largestT)
        {
            for(int j = 0; j < 4; j++)
            {
                p->data.t++;
                p = p->next;
            }

            p->data.pageNum = pageNum;
            count++;
            p->data.t = 0;

            printf("指令地址:%d \n", virAddr);
            printf("指令未裝入記憶體且記憶體塊已滿!頁面置換完成!\n使用者指令第%d頁第%d條的實體地址為:第%d塊第%d條 \n\n", pageNum, (virAddr % 10), p->data.blockNum, (virAddr % 10));

            return 1;
        }

        p = p->next;
    }

    return 1;
}

void calculate() //計算缺頁率
{
    for(int i = 0; i < 320; i++)
    {
        LRU(pageAddr[i], instrAddr[i]);
    }

    printf("\n");
    printf("缺頁次數:%.0f\n", count);
    printf("計算得到的缺頁率為:%.4f \n", count / 320);
}

int main()
{
    printf("----------最近最久未使用置換演算法----------\n\n");

    initialize();
    calculate();

    return 0;
}

相關文章