可变分区的存储管理
一. 实验目的
可变分区分配是一种重要的存储管理思想,目前流行的操作系统采用的分段存储管理的基本思想就源自该方法。本实验的目的是通过编程来模拟一个简单的可变分区分配存储管理系统,经过实验者亲自动手编写管理程序,可以进一步加深对可变分区分配存储管理方案设计思想的理解。
二. 实验内容
(1)编程实现简单的可变分区分配存储管理系统。要求:
a) 建立描述作业和内存分区的数据结构。
b) 初始信息输入,包括内存初始大小、各作业信息、使用哪种分区分配算法等。这些信息可以直接从键盘上输入,也可以从文件读取。
c) 程序实现空闲分区分配算法,程序初始化或运行过程中都应能指定算法。
d) 编程实现分区回收算法,对实验列出的几种分区回收情况都应该能处理。
e) 程序应能根据自己的内部时钟、作业到达时间和需要执行的时间,决定作业何时执行结束,并回收分区。
f) 实现分区移动算法,能在需要的时候合并空闲区。
g) 高级功能:为系统添加作业调度算法。
(2)使用本程序执行下面的一批作业,观察内存的分配和回收情况。系统可用内存的大小为2560K。
作业号 |
到达时间 |
执行时间 |
要求执行空间 |
J1 |
0 |
15 |
600k |
J2 |
1 |
8 |
1000k |
J3 |
2 |
40 |
300k |
J4 |
3 |
30 |
700k |
J5 |
4 |
20 |
500k |
三. 实验结论
1. 算法理解
可变分区分配可以根据进程实际的需要,动态的为之分配内存空间。为实现这一操作,需要涉及到建立分区数据结构,选择分区分配算法以及分区的分配与回收的功能。因此,为了能让各个分区形成一个动态的数据结构,可以用动态分区链来记录每个分区的信息,并用后指针将各个分区链接起来,通过移动前后指针从而实现对分区的动态分配与回收。
2. 实验过程
1)、 建立描述作业与分区的数据结构
(1)、用结构体数组存储作业信息
每个作业包括作业号、作业到达时间、作业执行时间和需要内存空间四个信息。将这些信息在结构体中用相应的标识符进行声明。然后,创建一个结构体类型的数组用来存储多个作业相应的信息。代码实现如下:
typedef struct Work { int id; //作业号 int atTime; //到达时间 int runTime; //执行时间 int needSize; //需要执行空间 }WORK; WORK workList[1001];
(2)、用结构体链表存储分区信息
在可变分区存储管理中,分区的状态可以分为两种,空闲和被占用。在结构体中用state来表示分区的状态。其它分区信息如:起始地址、分区大小也用相应的标识符表示。另外,因为需要链表结构,因此在结构体中需要声明一个结构体指针类型变量,用于指向下一个链表节点。具体代码实现如下:
typedef struct AreaNode *AreaList; typedef struct AreaNode { int id; //占用作业 int addr; //分区起始地址 int size; //分区大小 int state; //分区状态,0表示空闲,1表示被占用 AreaList next; //后指针 }AREANODE;
(3)、为链表申请动态空间
使用malloc函数从堆上分配内存,并返回内存的首地址赋值给头指针变量head。而且malloc对应的释放内存的函数是free函数,方便后面内存的回收。由于程序中有多次需要申请内存的请求,为避免代码重复可以声明一个函数用于返回申请内存后的指针地址,然后用相应的指针变量接收。申请内存函数getMallocArea()代码如下:
AreaList getMallocArea() { return (AreaList)malloc(sizeof(AREANODE)); }
2)、初始化信息输入
(1)、创建链表头节点,并为其申请内存空间和赋初始值
初始分区内存为整块内存空间,定义内存空间固定值MEMORY_SIZE为2560k。
AreaList head; //头节点 head = getMallocArea(); head->addr = 0; head->next = NULL; head->size = MEMORY_SIZE; head->state = 0;
(2)、初始化作业数组
使用循环结构,规定一共有5个作业,在每次循环为每个作业输入初始值。另外,在每次循环计算每个作业的工作截止时间,并将最大值赋值给全局变量timeMax作为结束程序的依据。
for (int i = 0; i < 5; i++) { cin >> workList[i].id >> workList[i].atTime >> workList[i].runTime >> workList[i].needSize; if (timeMAX < (workList[i].atTime + workList[i].runTime)) { timeMAX = workList[i].atTime + workList[i].runTime; } }
3)、三种动态分区分配算法的实现
(1)、首次适应算法ffFindFreeArea(workList[i], p)
首次适应算法分配内存,从链首开始查找,直至找到大小能满足要求的空闲分区为止。如果分区内存有剩余,则建立一个新的链表节点将已占用区域和空闲区域分开,并将空闲节点接在已占用节点之后。如果搜索到链尾也找不到满足要求的分区则返回作业,提交错误。具体实现代码如下:
while (p != NULL) { //从头扫描到尾 //判断作业是否能在该分区分配 if ((work.needSize < p->size) && p->state == 0) { //将作业放到分区中,即更新分区的值 p->id = work.id; p->state = 1; AreaList add; //增加一个链表,作为后继链表 add = getMallocArea(); add->addr = p->addr + work.needSize; //初始化新节点 add->size = p->size - work.needSize; add->state = 0; add->next = p->next; p->next = add; //p节点后连接新空闲节点add p->size = work.needSize; break; } //如果剩余空间大小正好和作业所需空间相同,不用在申请新节点 else if (work.needSize == p->size && p->state == 0) { p->id = work.id; p->state = 1; break; } //如果剩余空间不足以分配给需要的作业,返回错误 else if (work.needSize > p->size && p->state == 0) { cout << "\nERROR(0)--" << "作业:J" << work.id << " 所需空间太大,无法分配足够内存,请重新申请!" << endl; break; } p = p->next; }
(2)、最佳适应算法bfFindFreeArea(workList[i], p, head)
最佳适应算法是每次把满足要求的最小的空闲分区分配给作业。因此可以先遍历一遍链表,找到空闲的分区就标记下来其空间大小并与需要分配的作业空间求差找到其最小值mixsub。通过一个记录指针len,定位到所满足要求且插值sub最小的分区。实现代码如下:
while (p != NULL) { //直到链表节点空闲且所需内存足够 if (p->state == 0 && p->size >= work.needSize) { sub = p->size - work.needSize; if (flag == 0) { //标志着第一个存作业的链表 minsub = sub; location = len; //记录链表位置 } //从多个链表找出一个内存只差最小 else { if (sub < minsub) { minsub = sub; location = len; //记录链表位置 } } flag++; } len++; //表示节点位置后移 p = p->next; }
遍历过程结束后,即可以得到分区与作业所需空间的最小差minsub以及满足最佳分配算法的分区的位置location。找到这一分区,如果mixsub大于获等于0,则说明分区存在,作业可以被分配,然后就可以修改分区的状态为被占用并将作业号写入链表节点中。代码实现如下:
if (minsub >= 0) { p = head; //初始化p链表 //从头开始,直到找到第location个链表节点 for (int i = 0; i < location; i++) { p = p->next; //p指向能放进进程且两者内存之差最小的链表节点 } if (minsub > 0) { p->id = work.id; p->state = 1; AreaList add; //增加一个链表,作为后继链表 add = getMallocArea(); add->addr = p->addr + work.needSize; //初始化新节点 add->size = p->size - work.needSize; add->state = 0; add->next = p->next; p->next = add; //p节点后连接新空闲节点add p->size = work.needSize; } else { //所需内存正好满足 p->id = work.id; p->state = 1; } } else { cout << "\nERROR(0)--" << "作业:J" << work.id << " 所需空间太大,无法分配足够内存,请重新申请!" << endl; } }
(3)最坏适应算法wfFindFreeArea(workList[i], p, head)
最坏适应算法选择空闲分区分配的策略正好和最佳适应算法相反,它在扫描整个分区链时,总是选择满足要去且内存最大的空闲分区。因此,此部分的程序设计和最佳适应算法的步骤基本相同,只是在标记分区时,依据的时分区内存与作业所需空间的最大值maxsub。在这里不再赘述。
4)、内存回收的实现void freeArea(WORK work, AreaList p)
当进程运行完毕释放内存时,系统根据回收区的首址,从空闲区链表中找到相应的插入点,为了合理的释放内存预先定义好两个结构体指针变量用于实现分区的合并操作。
AreaList pPre = nullptr, pNext = nullptr; //pPre是p的上一个链表
在释放内存时,会遇到相邻表项具有不同的状态,采用不同的方法去解决
(1)、当分区处在链首时,会遇到三种情况:1、链尾指针指向空,意思为此分区即为整片内存,直接把状态设为空闲;2、链尾指针不为空且后一节点分区状态为被占用,此时不用对容量改变,直接改变此分区的状态即可。第1、2种情况操作为:
p->state = 0;
3、链尾指针不为空且后一节点状态为空闲,则将此分区的尾指针指向下一分区的尾部,把分区大小再加上后一分区的容量并设置状态为空闲。
pNext = p->next; p->state = 0; //删除后一节点,p节点大小增加 p->next = pNext->next; p->size += pNext->size; free(pNext);
(2)、当分区处在链表中间时,存在四种情况。先初始化pNext节点指向p节点的后一分区,pPre节点指向p节点的前一分区。
1、当pPre和pNext都不为空时,直接设置p节点状态为空闲
p->state = 0;
2、当只有pPre为空时,p节点向前合并,并释放p
pPre->next = p->next;
pPre->size += p->size;
free(p);
3、当只有pNext为空时,p节点向后合并,并释放p
pPre->next = p->next;
pNext->size += p->size;
pNext->addr = p->addr;
free(p);
4、当pPre和pNext都空闲时,p节点和pNext节点一起向前合并,并释放掉p和pNext
pPre->next = pNext->next;
pPre->size += p->size + pNext->size;
free(p);
free(pNext);
(3)、当分区位于链尾时,如果前一节点被占用,则直接改变状态;若前一节点为空闲,则向前合并,并释放p
pPre->next = p->next;
pPre->state = 0;
pPre->size += p->size;
free(p);
5)、实现对分配算法的选择以及对已执行完成分区的回收的调用函数selectFun()
(1)、声明标志量select,做到可以根据输入的信息调用相应的分配算法函数。可以用switch结构实现。
switch (select) { case 1: ffFindFreeArea(workList[i], p); //首次适应算法 break; case 2: bfFindFreeArea(workList[i], p, head); //最佳适应算法 break; default: wfFindFreeArea(workList[i], p, head); //最坏适应算法 break; }
(2)、声明runtime变量并赋初始值0,随着程序运行,该变量不断加一,当其值与timeMax相等时,结束程序运行。
程序从未作业分配内存时就开始运行时间片,并在每个时间片内遍历作业结构体数组,找到执行时间已完成的作业将其占用的内存空间调用freeArea()函数释放掉。实现如下:
for (int i = 0; i < 5; i++) { //到达作业的执行时间就释放掉 if ((runtime - workList[i].atTime) == workList[i].runTime) { freeArea(workList[i], p); } }
每次时间片结束后,调用outAreaNode()函数用来返回当前内存链表的使用情况。与分配作业所消耗的时间分开,在此之后利用while循环语句执行时间过程。代码如下:
while (flag) { //运行时间片 for (int i = 0; i < 5; i++) { //到达作业的执行时间就释放掉 if ((runtime - workList[i].atTime) == workList[i].runTime) { freeArea(workList[i], p); } } if (runtime <= timeMAX) { outAreaNode(p, runtime); runtime++; } else { flag = 0; //运行时间和做作业中所需时间最大值相等,结束时间片 } }
3. 实验结果
(1)、首次适应算法运行结果
首先输入作业信息,选择相应算法调用接口函数
图1 初始信息输入
输入1后,程序开始使用首次适应算法为作业分配分区,初始分配过程如下图所示。
图2 初始运行结果
由结果可以看出,刚开始作业1、2和3都按照最先适应算法获得相应的分区。但可以看到作业4被程序退回,原因是内存剩余空间不足以存放作业4。当执行到第4个时间片时,作业5也进入了内存成功的被分配了相应的内存分区,如下图所示。
图3 作业5的分配
(2)、最佳适应算法运行结果
输入作业的初始信息,选择相应的算法运行程序
图4 初始信息输入
当时间片开始运行时,作业1和作业2都按顺序插入,但是到达第2个时间片时,作业1被回收(如图5所示),同时剩下两个空闲分区。而这时作业3被分配进来,因为作业3的所需容量比第一个空闲分区容量要大,所以选择了作业2后面的一个容量更大的分区。
图5 时间片0-2
运行到第3个时间片时,作业3被回收,作业4被分配到了空闲的两个分区中容量更小的分区,如下图6所示。
图6 时间片4-6
由运行结果可已看出,程序算法满足了最佳适应算法的要求。
(3)、最坏适应算法执行结果
输入最初的作业信息,选择相应的算法运行程序
图7 初始信息输入
当程序运行到第2个时间片时,作业1被释放,作业3被分配到两个空闲分区容量更大的分区中。到了第3个时间片时,作业3被回收,作业4也同样被分配到了更大的分区中。
图8 时间片1-3
由运行结果可已看出,程序算法满足了最坏适应算法的要求。
(4)、分区回收运行示例
以最先适应算法执行结果为例,查看当中的回收情况。
如下图所示,8到9时间片出现了要释放的分区的前后分区都不空闲的情况。此时程序直接将要释放的分区状态改为空闲状态。
图 时间片8-9
当运行到第14个时间片时,作业1也将要被回收,过程如下图所示。
图 时间片14-15
可以从图中看出,要回收的分区处于链首,且后一分区为空闲分区。程序将作业1所占的分区和后一分区合并为一个分区,且状态设为了空闲。
当运行到第23个时间片时,作业5所在的分区将要被释放,这种情况属于要释放分区处在链表中间,且相邻的后一节点为空,如下图所示。
图 时间片23-24
程序对作业5所做的操作即分区向后合并,形成更大的空闲分区。
当运行到第41个时间片时,作业3所在的分区被释放,此时分区的前后节点都为空闲状态。
图 时间片40-42
由结果看出,程序将分区合并为整个分区,至此所有已分配的作业执行完毕,整个内存空间全部空闲。
4. 实验总结
本次实验实现了动态分区分配算法,并能通过c++语言熟练的模拟算法对进程操作的过程。在代码中通过对程序不断地试错、调试,最终理解了算法的过程与思想并且也终于达到了所期望的结果。
附录
1 #include <iostream> 2 #include <iomanip> 3 4 #define MEMORY_SIZE 2560 5 6 using namespace std; 7 8 //内存结构体 9 typedef struct AreaNode *AreaList; 10 typedef struct AreaNode { 11 int id; //占用作业 12 int addr; //分区起始地址 13 // int endr; //结束地址 14 int size; //分区大小 15 int state; //分区状态,0表示空闲,1表示被占用 16 // AreaList pre; //前指针 17 AreaList next; //后指针 18 }AREANODE; 19 AreaList head; //头节点 20 21 //作业结构体 22 typedef struct Work { 23 int id; //作业号 24 int atTime; //到达时间 25 int runTime; //执行时间 26 int needSize; //需要执行空间 27 }WORK; 28 WORK workList[1001]; 29 int timeMAX = 0; //作业中在时间片最后运行时间最大值 30 31 //为结构体申请动态空间 32 AreaList getMallocArea() { 33 return (AreaList)malloc(sizeof(AREANODE)); 34 } 35 36 //输入作业信息 37 void inWork() { 38 cout << "请输入作业信息:" << endl; 39 cout << "作业号 " << "到达时间 " << "执行时间 " << "所需执行空间 " << endl; 40 for (int i = 0; i < 5; i++) 41 { 42 cin >> workList[i].id >> workList[i].atTime >> workList[i].runTime >> workList[i].needSize; 43 if (timeMAX < (workList[i].atTime + workList[i].runTime)) { 44 timeMAX = workList[i].atTime + workList[i].runTime; 45 } 46 } 47 } 48 49 //首次适应实现 50 void ffFindFreeArea(WORK work, AreaList p) { 51 while (p != NULL) { //从头扫描到尾 52 //判断作业是否能在该分区分配 53 if ((work.needSize < p->size) && p->state == 0) { 54 //将作业放到分区中,即更新分区的值 55 p->id = work.id; 56 p->state = 1; 57 58 AreaList add; //增加一个链表,作为后继链表 59 add = getMallocArea(); 60 add->addr = p->addr + work.needSize; //初始化新节点 61 add->size = p->size - work.needSize; 62 add->state = 0; 63 64 add->next = p->next; 65 p->next = add; //p节点后连接新空闲节点add 66 p->size = work.needSize; 67 break; 68 } //如果剩余空间大小正好和作业所需空间相同,不用在申请新节点 69 else if (work.needSize == p->size && p->state == 0) { 70 p->id = work.id; 71 p->state = 1; 72 break; 73 } //如果剩余空间不足以分配给需要的作业,返回错误 74 else if (work.needSize > p->size && p->state == 0) { 75 cout << "\nERROR(0)--" << "作业:J" << work.id << " 所需空间太大,无法分配足够内存,请重新申请!" << endl; 76 break; 77 } 78 p = p->next; 79 } 80 } 81 82 //最佳适应实现 83 void bfFindFreeArea(WORK work, AreaList p, AreaList head) { 84 int sub = -1; //分区链表节点内存与将要分配进程内存之差 85 int minsub = -1; //分区链表节点内存与将要分配进程内存之差最小值 86 int flag = 0; //标记是否是第一次适应 87 int location = 0; //记录最小差的链表位置 88 int len = 0; //记录链表节点位置 89 90 while (p != NULL) { 91 //直到链表节点空闲且所需内存足够 92 if (p->state == 0 && p->size >= work.needSize) { 93 sub = p->size - work.needSize; 94 if (flag == 0) { //标志着第一个存作业的链表 95 minsub = sub; 96 location = len; //记录链表位置 97 } //从多个链表找出一个内存只差最小 98 else { 99 if (sub < minsub) { 100 minsub = sub; 101 location = len; //记录链表位置 102 } 103 } 104 flag++; 105 } 106 len++; //表示节点位置后移 107 p = p->next; 108 } 109 110 //当最小差大于0时,存入进程 111 if (minsub >= 0) { 112 p = head; //初始化p链表 113 //从头开始,直到找到第location个链表节点 114 for (int i = 0; i < location; i++) 115 { 116 p = p->next; //p指向能放进进程且两者内存之差最小的链表节点 117 } 118 119 if (minsub > 0) { 120 p->id = work.id; 121 p->state = 1; 122 123 AreaList add; //增加一个链表,作为后继链表 124 add = getMallocArea(); 125 add->addr = p->addr + work.needSize; //初始化新节点 126 add->size = p->size - work.needSize; 127 add->state = 0; 128 129 add->next = p->next; 130 p->next = add; //p节点后连接新空闲节点add 131 p->size = work.needSize; 132 } 133 else { //所需内存正好满足 134 p->id = work.id; 135 p->state = 1; 136 } 137 } 138 else { 139 cout << "\nERROR(0)--" << "作业:J" << work.id << " 所需空间太大,无法分配足够内存,请重新申请!" << endl; 140 } 141 } 142 143 //最坏适应实现 144 void wfFindFreeArea(WORK work, AreaList p, AreaList head) { 145 int sub = -1; //分区链表节点内存与将要分配进程内存之差 146 int maxsub = -1; //分区链表节点内存与将要分配进程内存之差最大值 147 int flag = 0; //标记是否是第一次适应 148 int location = 0; //记录最大差的链表位置 149 int len = 0; //记录链表节点位置 150 151 while (p != NULL) { 152 //直到链表节点空闲且所需内存足够 153 if (p->state == 0 && p->size >= work.needSize) { 154 sub = p->size - work.needSize; 155 if (flag == 0) { //标志着第一个存作业的链表 156 maxsub = sub; 157 location = len; //记录链表位置 158 } //从多个链表找出一个内存只差最大 159 else { 160 if (sub > maxsub) { 161 maxsub = sub; 162 location = len; //记录链表位置 163 } 164 } 165 flag++; 166 } 167 len++; //表示节点位置后移 168 p = p->next; 169 } 170 171 //当最大差大于0时,存入进程 172 if (maxsub >= 0) { 173 p = head; //初始化p链表 174 //从头开始,直到找到第location个链表节点 175 for (int i = 0; i < location; i++) 176 { 177 p = p->next; //p指向能放进进程且两者内存之差最大的链表节点 178 } 179 180 if (maxsub > 0) { 181 p->id = work.id; 182 p->state = 1; 183 184 AreaList add; //增加一个链表,作为后继链表 185 add = getMallocArea(); 186 add->addr = p->addr + work.needSize; //初始化新节点 187 add->size = p->size - work.needSize; 188 add->state = 0; 189 190 add->next = p->next; 191 p->next = add; //p节点后连接新空闲节点add 192 p->size = work.needSize; 193 } 194 else { //所需内存正好满足 195 p->id = work.id; 196 p->state = 1; 197 } 198 } 199 else { 200 cout << "\nERROR(0)--" << "作业:J" << work.id << " 所需空间太大,无法分配足够内存,请重新申请!" << endl; 201 } 202 } 203 204 //释放已完成作业所占用的空间 205 void freeArea(WORK work, AreaList p) { 206 int count = 0; //记录所找作业位置 207 AreaList pPre = nullptr, pNext = nullptr; //pPre是p的上一个链表 208 209 while (p != NULL) { 210 //找到目标作业 211 if (p->id == work.id) { 212 //释放分配区在链表首部 213 if (count == 0) { 214 if (p->next != NULL) { 215 pNext = p->next; 216 if (pNext->state == 0) { //判断后面节点是否空闲 217 p->state = 0; 218 //删除后一节点,p节点大小增加 219 p->next = pNext->next; 220 p->size += pNext->size; 221 free(pNext); 222 break; 223 } 224 else { 225 p->state = 0; 226 break; 227 } 228 } 229 else { 230 p->state = 0; 231 break; 232 } 233 } //释放分配区在链表中间 234 else if (p->next != NULL) { 235 pNext = p->next; 236 //前后节点都不空闲 237 if (pPre->state == 1 && pNext->state == 1) { 238 p->state = 0; 239 break; 240 } //只是后面节点被占用,则向前合并 241 else if (pPre->state == 0 && pNext->state == 1) { 242 pPre->next = p->next; 243 pPre->size += p->size; 244 free(p); 245 break; 246 } //只是前一节点被占用,向后合并 247 else if (pPre->state == 1 && pNext->state == 0) { 248 pPre->next = p->next; 249 pNext->size += p->size; 250 pNext->addr = p->addr; 251 free(p); 252 break; 253 } //前后节点都空闲 254 else if (pPre->state == 0 && pNext->state == 0) { 255 pPre->next = pNext->next; 256 pPre->size += p->size + pNext->size; 257 free(p); 258 free(pNext); 259 break; 260 } 261 } //释放分配区在链表尾 262 else if (p->next == NULL) { 263 //前一个节点被占用 264 if (pPre->state == 1) { 265 p->state = 0; 266 break; 267 } //前一节点空闲 268 else { 269 pPre->next = p->next; 270 pPre->state = 0; 271 pPre->size += p->size; 272 free(p); 273 break; 274 } 275 } 276 } 277 278 pPre = p; //pPre指向下次遍历的p指向的前一个节点 279 p = p->next; 280 count++; 281 } 282 } 283 284 //输出内存使用情况 285 void outAreaNode(AreaList p, int runtime) { 286 cout << "\n" << runtime << "---------------------------------------------------------------\n"; 287 cout << "占用作业号id\t" << "分区起始地址addr\t" 288 << "分区大小size\t\t" << "分区状态state\t" << endl; 289 while (p != NULL) { 290 if (p->state == 1) { //非空闲 291 cout << p->id << "\t\t\t " << p->addr << "\t\t\t " 292 << p->size << "\t\t\t " << p->state << endl; 293 } //空闲 294 else { 295 cout << "无" << "\t\t\t " << p->addr << "\t\t\t " 296 << p->size << "\t\t\t " << p->state << endl; 297 } 298 p = p->next; 299 } 300 } 301 302 //选择算法函数 303 void selectFun(AreaList p, AreaList head) { 304 int select; 305 cin >> select; 306 cout << "内存运行情况如下:" << endl; 307 308 int runtime = 0; //记录运行时间 309 int flag = 1; //标志量,用来结束循环 310 for (int i = 0; i < 5; i++) 311 { //向内存写作业 312 switch (select) { 313 case 1: ffFindFreeArea(workList[i], p); //首次适应算法 314 break; 315 case 2: bfFindFreeArea(workList[i], p, head); //最佳适应算法 316 break; 317 default: wfFindFreeArea(workList[i], p, head); //最坏适应算法 318 break; 319 } 320 321 for (int i = 0; i < 5; i++) 322 { //到达作业的执行时间就释放掉 323 if ((runtime - workList[i].atTime) == workList[i].runTime) { 324 freeArea(workList[i], p); 325 } 326 } 327 outAreaNode(p, runtime); 328 runtime++; 329 } 330 while (flag) { //运行时间片 331 for (int i = 0; i < 5; i++) 332 { //到达作业的执行时间就释放掉 333 if ((runtime - workList[i].atTime) == workList[i].runTime) { 334 freeArea(workList[i], p); 335 } 336 } 337 338 if (runtime <= timeMAX) { 339 outAreaNode(p, runtime); 340 runtime++; 341 } 342 else { 343 flag = 0; //运行时间和做作业中所需时间最大值相等,结束时间片 344 } 345 } 346 } 347 348 int main(void) { 349 inWork(); 350 AreaList p; //尾节点 351 head = getMallocArea(); 352 head->addr = 0; 353 head->next = NULL; 354 head->size = MEMORY_SIZE; 355 // head->endr = head->size + head->addr - 1; 356 head->state = 0; 357 p = head; 358 359 cout << "选择要使用的分配算法:" << endl; 360 cout << "1、最先适应分配算法" << endl; 361 cout << "2、最优适应分配算法" << endl; 362 cout << "3、最坏适应分配算法" << endl; 363 364 selectFun(p, head); 365 366 return 0; 367 }