实战页式内存管理(上)

课程设计目标

用代码描述:页表,页框表,任务结构

用代码实现:页请求,页置换

模拟任务的页面访问过程(访问虚拟内存)

模拟操作系统中的任务调度(拓展)

实现的关键点一

页框表是全局唯一的,用于记录内存页使用情况

页表是任务私有的,用于记录虚拟页到内存页的映射关系

每一个任务需要一个结构体进行表示

实现的关键点二

页分配操作:int GetFrameItem(); 

页请求操作:int RequestPage(int pid, int page);

页交换操作:int SwapPage();

实现的关键点三

如何模拟不同的任务?

  • 不同任务的虚拟页访问顺序不同
  • 因此,可以随机产生页面访问序列

 具体的实现流程

#include <QCoreApplication>
#include <iostream>
#include <QList>
#include <ctime>

using namespace std;

#define PAGE_NUM   (0xFF + 1)
#define FRAME_NUM  (0x04)
#define FP_NONE    (-1)

struct FrameItem
{
    int pid;    // the task which use the frame
    int pnum;   // the page which the frame hold

    FrameItem()
    {
        pid = FP_NONE;
        pnum = FP_NONE;
    }
};

class PageTable
{
private:
    int m_pt[PAGE_NUM];

public:
    PageTable()
    {
        for(int i = 0; i < PAGE_NUM; i++)
        {
            m_pt[i] = FP_NONE;
        }
    }

    int& operator[](int i)
    {
        if((i >= 0) && (i < length()))
        {
            return m_pt[i];
        }

        QCoreApplication::exit(-1);
    }

    int length() const
    {
        return PAGE_NUM;
    }
};

class PCB
{
private:
    int m_pid;               // task id
    PageTable m_pageTable;   // page table for the task
    int* m_pageSerial;       // simulate the page serial access
    int m_pageSerialCount;   // page access count
    int m_next;              // the next page index to access

public:
    PCB(int pid)
    {
        m_pid = pid;
        m_pageSerialCount = qrand() % 5 + 5;
        m_pageSerial = new int[m_pageSerialCount];

        for(int i = 0; i < m_pageSerialCount; i++)
        {
            m_pageSerial[i] = qrand() % 8;
        }

        m_next = 0;
    }

    int getPid()
    {
        return m_pid;
    }

    PageTable& getPageTable()
    {
        return m_pageTable;
    }

    int getNextPage()
    {
        int ret = m_next++;

        if(ret < m_pageSerialCount)
        {
            ret = m_pageSerial[ret];
        }
        else
        {
            ret = FP_NONE;
        }

        return ret;
    }

    bool running()
    {
        return (m_next < m_pageSerialCount);
    }

    void printPageSerial()
    {
        QString s = "";

        for(int i = 0; i < m_pageSerialCount; i++)
        {
            s += QString::number(m_pageSerial[i]) + " ";
        }

        cout << "Task" << QString::number(m_pid).toStdString() << " : " << s.toStdString() << endl;
    }

    ~PCB()
    {
        delete[] m_pageSerial;
    }
};

FrameItem FrameTable[FRAME_NUM];
QList<PCB*> TaskTable;

int GetFrameItem();
void AccessPage(PCB& pcb);
int RequestPage(int pid, int page);
int SwapPage();
void PrintLog(QString log);
void PrintPageMap(int pid, int page, int frame);
void PrintFatalError(QString s, int pid, int page);

int GetFrameItem()
{
    int ret = FP_NONE;

    for(int i = 0; i < FRAME_NUM; i++)
    {
        if(FrameTable[i].pid == FP_NONE)
        {
            ret = i;
            break;
        }
    }

    return ret;
}

void AccessPage(PCB& pcb)
{
    int pid = pcb.getPid();
    PageTable& pagetable = pcb.getPageTable();
    int page = pcb.getNextPage();

    if(page != FP_NONE)
    {
        PrintLog("Access Task" + QString::number(pid) + " for page" + QString::number(page));

        if(pagetable[page] != FP_NONE)
        {
            PrintLog("Find target page in page table.");
            PrintPageMap(pid, page, pagetable[page]);
        }
        else
        {
            PrintLog("Target page is not found, need to request page ...");
            pagetable[page] = RequestPage(pid, page);

            if(pagetable[page] != FP_NONE)
            {
                PrintPageMap(pid, page, pagetable[page]);
            }
            else
            {
                PrintFatalError("Can NOT request page from disk ...", pid, page);
            }
        }
    }
    else
    {
        PrintLog("Task" + QString::number(pid) + " is finished!");
    }
}

int RequestPage(int pid, int page)
{
    int frame = GetFrameItem();

    if(frame != FP_NONE)
    {
        PrintLog("Get a frame to hold page content: Frame" + QString::number(frame));
    }
    else
    {
        PrintLog("No free frame to allocate, need to swap page out.");

        frame = SwapPage();

        if(frame != FP_NONE)
        {
            PrintLog("Succeed to swap lazy page out.");
        }
        else
        {
            PrintFatalError("Failed to swap page out.", pid, FP_NONE);
        }
    }

    PrintLog("Load content from disk to Frame" + QString::number(frame));

    FrameTable[frame].pid = pid;
    FrameTable[frame].pnum = page;

    return frame;
}

int Random()
{
    // just random select
    int obj = qrand() % FRAME_NUM;

    PrintLog("Random select a frame to swap page content out: Frame" + QString::number(obj));
    PrintLog("Writed the selected page content back to disk.");

    FrameTable[obj].pid = FP_NONE;
    FrameTable[obj].pnum = FP_NONE;

    for(int i = 0, f = 0; (i < TaskTable.count() && !f); i++)
    {
        PageTable& pt = TaskTable[i]->getPageTable();
        for(int j = 0; j < pt.length(); j++)
        {
            if(pt[j] == obj)
            {
                f = 1;
                pt[j] = FP_NONE;

                break;
            }
        }
    }

    return obj;
}

int SwapPage()
{
    return Random();
}

void RecycleTask(PCB& pcb)
{
    PrintLog("Task" + QString::number(pcb.getPid()) + " is finished ...");
    PageTable& pt = pcb.getPageTable();

    for(int i = 0; i < pt.length(); i++)
    {
        if(pt[i] != FP_NONE)
        {
            FrameTable[pt[i]].pid = FP_NONE;
            FrameTable[pt[i]].pnum = FP_NONE;

            PrintLog("Remove Frame" + QString::number(pt[i]));

            pt[i] = FP_NONE;
        }
    }
}

void PrintLog(QString log)
{
    cout << log.toStdString() << endl;
}

void PrintPageMap(int pid, int page, int frame)
{
    QString s = "";

    s += "Task" + QString::number(pid) + " : " + "Page" + QString::number(page) + " ==> " + "Frame" + QString::number(frame);

    cout << s.toStdString() << endl;
}

void PrintFatalError(QString s, int pid, int page)
{
    s += "Task" + QString::number(pid) + " : " + "Page" + QString::number(page);

    cout << s.toStdString() << endl;

    QCoreApplication::exit(-2);
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int index = 0;

    qsrand(time(NULL));

    TaskTable.append(new PCB(1));
    TaskTable.append(new PCB(2));

    PrintLog("Task Page Serial:");

    for(int i = 0; i < TaskTable.count(); i++)
    {
        TaskTable[i]->printPageSerial();
    }

    PrintLog("=======Running=======");

    while(true)
    {
        if(TaskTable.count() > 0)
        {
            if(TaskTable[index]->running())
            {
                AccessPage(*TaskTable[index]);        
            }
            else
            {
                RecycleTask(*TaskTable[index]);
            }
        }

        if(TaskTable.count() > 0)
        {
            index = qrand() % TaskTable.count();
        }

        cin.get();
    }

    return a.exec();
}

8-10行定义了三个常量,我们把一个任务的最多的页表数量定义为256,页框的最大数量定义为4,FP_NONE表明这个页表号或者页框号未被使用。

12行-22行定义了页框项,它有两个成员变量,一个是拥有此页框的任务id,另一个是与此页框相关联的页表。

24-52行定义了页表,它里面定义了从页表号到页框号的映射,这里采用的是单级映射。

54-125行定义了任务控制块,有5个成员变量,第一个为任务的id号,第二个为页表中的页号,第三个为需要访问的页表号的数组,第四个为需要访问页表号的数量,第五个为下一个需要访问的页表号。在这里,我们设计得比较简单,需要访问页表号的数量和页表值都是随机产生的。

127行,我们定义了页框表,128行,我们定义了一个链表来存储任务控制块。

138行这个函数的作用:用来返回空闲的页框号。

154行这个函数的作用:模拟一次页访问。

189行这个函数的作用:完成一次页请求。

221行这个函数的作用:当前的页框已经满了,我们随机产生一个index,把FrameTable[index]所对应的页框移除。注意:要把清除相对应的页表相关映射信息。

255行这个函数的作用:当一个任务结束时,我们需要清理它所占用的页框项。以供其他任务使用。

在main函数里,我们定义了两个任务,在while循环里,模拟这两个任务的页请求。宏观上,这两个任务是并行执行的。当任务结束时,我们清理该任务对应的页框项。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值