设计一个动态分区式存贮区管理程序,要求支持不同的放置策略。如首次、最佳、最坏。
说明:
(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节,在代码计算地址时添加这个关键的1。
实习心得:书中所用例子为已分配进程在低地址区,而本题已分配进程在高地址区,让我对动态分区式存贮区管理有了更深层次的理解,