操作系统原理动态分区式存贮区管理

文章目录

  • 一、题目要求
  • 二、程序功能及设计思路
  • 三、数据结构及算法设计
  • 四、程序运行情况
  • 五、遇到的困难及解决办法、实习心得或良好建议


一、题目要求

设计一个动态分区式存贮区管理程序,要求支持不同的放置策略。如首次、最佳、最坏。
说明:
(1) 分区描述器 rd 如下:
flag size next
要求空闲区队列按链表组织。
主存大小假设为 maxsize(单位为节=rd 的大小)。
(2) 主程序结构如下: 输入放置策略–申请一块内存作为主存–循环处理用户的请求(包括申请、释放)
需设计两个函数处理用户请求: 申请函数 Addr=Request(size)
释放函数 Release(addr)
(3)数据实例:maxsize=512 J1 申请162,J2 申请64,J3 申请120,J4 申请86,J1完成,J3完成,J5申请 72,J6申请100,J2完成,J7申请36,J8申请60,J4完成,J9申请110, J10申请42。备注:
(a)所有大小其单位为节(1 节=rd 的大小)
(b)作业申请 n 节,实际分配的分区大小应为 n+1 节。 其中一节作为分区描述器,其他 n 节提供给作业。
(c)已分配区放在高地址处。
(d)合并时应考虑四种情况: 假设回收区为 r,上邻 为 f1(f1 需搜索自由主存队列),下邻为 f2(f2 可直 接计算)
A)f1空闲,f2已分配;
B)f1已分配,f2空闲;
C)f1空闲,f2空闲;
D)f1已分配,f2已分配;

二、程序功能及设计思路

需求分析:空闲区队列按链表组织,且需要设计申请函数和释放函数,分区描述器占一节,已分配区在高地址处,合并时需要考虑多种情况。而申请函数又包含三种方式,所以每种方式遍历链表的操作必然不同。
所以程序应该有创建分区链表,申请内存和释放内存的功能。
设计思路:创建分区描述器类,进程类和一个管理类。管理类中包含各种适应算法和释放算法,同时创建一个进程类类型的vecotr数组,用来存储所有已经申请成功的进程,为释放算法作基础。
首次适应算法比较简单,直接根据申请顺序往主存中塞入即可。
最佳适应算法,则设计一个变量通过比较来记录当前遍历过的链表中内存最小的块,从而实现算法。
最坏适应算法,同理,设计一个变量通过比较来记录当前遍历过的链表中内存最大的块,从而实现算法。

三、数据结构及算法设计

(1)设计:数据结构
分区描述器应该具有分配标志,对空闲分区而言为0,对已分配区而言为1。同时也应该具有空闲区大小和勾链字,勾链字指向队列中下一个空闲分区,对已分配区而言,此项为0.

分区描述器类

class Rd { 
public:
    bool m_flag;//分配标志
    int m_size;//空闲区大小
    Rd *m_next;//勾链字 
    Rd(bool flag, int size, Rd* next) {
        m_flag = flag;
        m_size = size;
        m_next = next;
    }
    ~Rd(){}
};

进程具有进程名,首地址和程序大小三个特征。
进程类

class Proceedings
{
public:
    string m_name;//进程名
    int m_begin;//首地址
    int m_size;//程序大小
public:
    Proceedings(string name, int begin, int size) {
        m_name = name;
        m_begin = begin;
        m_size = size;
    }
    ~Proceedings() {}
};

管理类除包含各种算法外,应该有一指针指向分区链表的第一个节点,也需要一个容器来存储所有已经申请成功的进程。
管理类

class Manage {
    Rd* m_first; //指向分区链表的第一个节点
    vector<Proceedings>all; //存储所有已经申请成功的进程
public:
    Manage(Rd* first) :m_first(first) {}
    void first_adapt();//首次适应算法
    void BestWay();//最佳适应算法
    void WorstWay();//最坏适应算法
    void Read();
    void Release();//释放合并函数
};

(2)算法设计
首次适应算法

void Manage::first_adapt()
{
    int address=0;//address记录当前块的地址
    cout << "输入程序名和进程区的大小:";
    string name;
    int  size;
    cin >> name >> size;
    Rd* p(m_first);
    while (p) 
    {
        address =address+(p->m_size + 1);//注意分区描述器占1节
        if (p->m_flag==0)
        {
            if (p->m_size == size)
            {
                p->m_flag =1;
                address =address- size - 1;//正好占完空闲区
                break;
            }
            else if(p->m_size > size) //当前块大于进程申请的大小 
            {
                p->m_size = p->m_size-size- 1;
                address = address - size - 1;
                Rd *newRd = new Rd(1, size, p->m_next);
                p->m_next = newRd;//塞入后更新p的信息
                break;
            }
            else { p = p->m_next; }
        }
        else { p = p->m_next; }
    }
    if (p!=nullptr)//循环结束后,若p不为空,说明进程成功申请,将其加入vector
    {
      Proceedings newProceedings(name, size, address);
        all.push_back(newProceedings);
    }
    else {
        cout << "分配失败" << endl;
    }
}

最佳适应算法

void Manage::BestWay()
{
    int address(0);//address记录当前块的地址
    cout << "输入程序名和进程区的大小:";
    string name;
    int  size;
    cin >> name >> size;
    Rd* p(m_first);
    int max = 10000;
    Rd  *q(NULL);          //记录指针
    while (p)
    {
        if (p->m_flag==0)
        {
            if (p->m_size > size) //当前块大于进程申请的大小 
            {
                if (p->m_size < max) //当前块更适合
                {
                    max = p->m_size;
                    q = p;
                }
            }
            else if(p->m_size == size)//当前块正好等于进程申请的大小
            {
                p->m_flag = 1;
                q = p;
                break;
            }
        }
        p = p->m_next;
    }
    if (q) //循环结束后,若q不为空,则说明进程成功申请,将其加入vector
    {
        q->m_size -= (size + 1);
        Rd *newRd = new Rd(1, size, q->m_next);
        q->m_next = newRd;
        p = m_first;
        while (p) {
            if (p == q->m_next) { break; }
            address += (p->m_size + 1);
            p = p->m_next;
        }
        Proceedings newProceedings(name, size, address);
        all.push_back(newProceedings);
    }
    else { cout << "分配失败" << endl; }

最坏适应算法

void Manage::WorstWay()
{
    int address = 0;//address记录当前块的地址
    cout << "输入程序名和进程区的大小:";
    string name;
    int  size;
    cin >> name >> size;
    Rd* p(m_first);
    int min = 0;
    Rd* q(NULL);          //记录指针
    while (p)
    {
        if (p->m_flag==0)
        {
            if (p->m_size > size) //当前块大于进程申请的大小 
            {
                if (p->m_size > min) //当前块更小
                {
                    min = p->m_size;
                    q = p;
                }
            }
            else if(p->m_size == size)
            {
                p->m_flag = false;
                q = p;
                break;
            }
        }
        p = p->m_next;
    }
    if (q)//循环结束后,若q不为空,则说明进程成功申请,将其加入vector
    {
        q->m_size -= (size + 1);
        Rd* newRd = new Rd(1, size, q->m_next);
        q->m_next = newRd;
        p = m_first;
        while (p)
        {
            if (p == q->m_next)break;
            address += (p->m_size + 1);
            p = p->m_next;
        }
        Proceedings newProceedings(name, size, address);
        all.push_back(newProceedings);
    }
    else {  cout<< "分配失败" << endl; }
}

释放算法

void Manage::Release() {
    cout << "输入释放进程的id:";
    string name;
    cin >> name;
    //在vector中查找是否存在该进程 
    vector<Proceedings>::iterator it;
    for (it = all.begin(); it != all.end(); it++)
    {
        if (it->m_name == name) {
            break;
        }
    }
    if (it == all.end())
    {
        cout << "该进程不存在,请检查输入" << endl;
        return;
    }
    int address=0;
    Rd* p(m_first);
    while (p) {                      //查找该进程所用的分区 
        if (it->m_size == address)break;
        address += (p->m_size + 1);
        p = p->m_next;
    }
    p->m_flag = 0;                                //该块的状态更改为可用
    if (p->m_next)
    {
        if (p->m_next->m_flag == 0)   //若所释放的分区后面存在可用的分区,合并
        {
            p->m_size += (p->m_next->m_size + 1);
            Rd* t(p->m_next);
            p->m_next = p->m_next->m_next;
            delete t;
        }
    }
    Rd* q(m_first);
    while (q) {
        if (q->m_next == p && q->m_flag == 0){//所释放的分区前面存在可用的分区,合并       
            q->m_size += (p->m_size + 1);
        q->m_next = p->m_next;
        delete p;
        break;
    }
    q = q->m_next;
}
all.erase(it);
}

阅读算法

void Manage::Read()
{
    int i = 1;
    int remainsize=512;
    Rd* temp = m_first;
    while (temp)
    {
        if (temp->m_flag == 0) { 
            cout << "第" << i << "块分区可用, "; 
        }
        else {
            cout << "第" << i << "块分区不可用, ";
        }
            cout << "大小为" << temp->m_size << endl;
        
        i++;
        temp = temp->m_next;
    }
    cout << endl;
    vector<Proceedings>::iterator it = all.begin();
    while (it != all.end()) {
        cout << "名为" << it->m_name << "的进程返回的地址为:";
        cout << it->m_size+1 << endl;
        it++;
    }
}

四、程序运行情况

操作系统原理动态分区式存贮区管理_第1张图片
操作系统原理动态分区式存贮区管理_第2张图片

五、遇到的困难及解决办法、实习心得或良好建议

遇到的困难:进程返回的地址总是会和应该返回的正确地址不符。
解决办法:通过多次调试,注意分区描述器占1节,在代码计算地址时添加这个关键的1。
实习心得:书中所用例子为已分配进程在低地址区,而本题已分配进程在高地址区,让我对动态分区式存贮区管理有了更深层次的理解,

你可能感兴趣的:(链表,数据结构,操作系统)