知识储备
分区存储
分区存储管理又有三种不同的方式:静态分区、可变分区、可重定位分区 。
静态分区
静态分区存储管理是预先把可分配的主存储器空间分割成若干个连续区域,每个区域的大小可以相同,也可以不同。为了说明各分区的分配和使用情况,存储管理需设置一张“主存分配表”。主存分配表指出各分区的起始地址和长度,表中的占用标志位用来指示该分区是否被占用了,当占用的标志位为“0”时,表示该分区尚未被占用。进行主存分配时总是选择那些标志为“0”的分区,当某一分区分配给一个作业后,则在占用标志栏填上占用该分区的作业名。采用静态分区存储管理,主存空间的利用不高。
可变分区
可变分区方式是按作业的大小来划分分区。当要装入一个作业时,根据作业需要的主存量查看主存中是否有足够的空间,若有,则按需要量分割一个分区分配给该作业;若无,则令该作业等待主存空间。由于分区的大小是按作业的实际需要量来定的,且分区的个数也是随机的,所以可以克服固定分区方式中的主存空间的浪费。
随着作业的装入、撤离,主存空间被分成许多个分区,有的分区被作业占用,而有的分区是空闲的。当一个新的作业要求装入时,必须找一个足够大的空闲区,把作业装入该区,如果找到的空闲区大于作业需要量,则作业装入后又把原来的空闲区分成两部分,一部分给作业占用了;另一部分又分成为一个较小的空闲区。当一作主行结束撤离时,它归还的区域如果与其它空闲区相邻,则可合成一个较大的空闲区,以利大作业的装入。
可变分区调度算法
1)首次适应算法。每次分配时,总是顺序查找未分配表,找到第一个能满足长度要求的空闲区为止。分割这个找到的未分配区,一部分分配给作业,另一部分仍为空闲区。这种分配算法可能将大的空间分割成小区,造成较多的主存“碎片”。
2)最佳适应算法。从空闲区中挑选一个能满足作业要求的最小分区,这样可保证不去分割一个更大的区域,使装入大作业时比较容易得到满足。采用这种分配算法时可把空闲区按大小以递增顺利排列,查找时总是从最小的一个区开始,直到找到一个满足要求的区为止。
3)最坏适应算法。挑选一个最大的空闲区分割给作业使用,这样可使剩下的空闲区不至于太小,这种算法对中、小作业是有利的。采用这种分配算法时可把空闲区按大小以递减顺利排列,查找时总是从最大的一个区开始。按这种方法,在收回一个分区时也必须对表格重新排列。
看了上面的文章,基本了解了这个算法的流程。
流程图:
结构体设计
分区信息结构
//分区结构体 设计失误 设计成双向的方便
typedef struct subareaNode
{
int saddr;//起始地址
int len;//长度
int flag;//标志
struct subareaNode * prev;
struct subareaNode * next;
}subareaNode;
主存区结构
//主存区结构
typedef struct mainStorageRegion
{
int saddr;//起始地址
int size;//长度
int subareaCount;//分区个数
subareaNode* data;
}mainStorageRegion;
作业结构体
//作业结构体
typedef struct jobNode
{
int saddr;//起始地址
int len;//长度
char name[100];//作业名
bool operator==(const jobNode& tjob){//重写==运算符 list.remove 才可以比较
if (tjob.name == name)//名字一致 表示为同一个作业
{
return true;
}
return false;
}
}job;
出现乱码的话 在mian.cpp内的 mian函数里的 PCOLOR 设为0即可 基本上所有g++都可以编译
windows上devc也可以用 需要将main.cpp 和 pro_printf.h放在同一目录
(ubuntu)linux也一样
结果展示:
添加作业
完整代码:
main.cpp
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <string.h>
#include <pthread.h>
#include <malloc.h>
#include <semaphore.h>
#include <queue>
#include <map>
#include <iterator>
#include <unistd.h>
#include <list>
#include "pro_printf.h"
/*时间太仓促 不做性能优化 结构设计也不够好 但是我也没法子瓦*/
#define BUSY 1
#define IDLE 0
using namespace std;
//分区结构体 设计失误 设计成双向的方便
typedef struct subareaNode
{
int saddr;//起始地址
int len;//长度
int flag;//标志
struct subareaNode * prev;
struct subareaNode * next;
}subareaNode;
//主存区结构
typedef struct mainStorageRegion
{
int saddr;//起始地址
int size;//长度
int subareaCount;//分区个数
subareaNode* data;
}mainStorageRegion;
//作业结构体
typedef struct jobNode
{
int saddr;//起始地址
int len;//长度
char name[100];//作业名
bool operator==(const jobNode& tjob){//重写==运算符 list.remove 才可以比较
if (tjob.name == name)//名字一致 表示为同一个作业
{
return true;
}
return false;
}
}job;
/*全局变量*/
subareaNode* subareaList;
mainStorageRegion* mainStorage;
int mainStorageSize = -1;
int exitFlag = 0;
map<string,job> jobMap;
list<job> waitJobList;//作业等待队列
int inited = 0;
subareaNode *getMaxIdleSubarea(){//获取最大空闲分区
subareaNode* tSubarea = mainStorage->data,*maxSubarea;
maxSubarea = (subareaNode*)malloc(sizeof(subareaNode));
maxSubarea->len = -1;
int flag = 0,dis = mainStorage->size;
while (tSubarea!=NULL)
{
if(tSubarea->len > maxSubarea->len && !tSubarea->flag){
maxSubarea = tSubarea;
}
tSubarea = tSubarea->next;
}
return maxSubarea;
}
//初始化数据
void init(){
if(inited){
cprintfln("已经初始化过了,是否继续?继续将清空分区表! y/其他表示放弃",L_RED);
char c;
cin >> c;
if(c=='y'){
inited = 0;
init();
return;
}else{
return;
}
}
cprintf("请输入主存区大小:",CYAN);
cin >> mainStorageSize;
mainStorage = (mainStorageRegion*)malloc(sizeof(mainStorageRegion));
mainStorage->saddr = 0;
mainStorage->size = mainStorageSize;
mainStorage->subareaCount = 1;
subareaList = (subareaNode*)malloc(sizeof(subareaNode));
subareaList->saddr = 0;
subareaList->len = mainStorageSize;
subareaList->prev=NULL;
subareaList->next=NULL;
subareaList->flag=IDLE;
waitJobList.clear();
jobMap.clear();
mainStorage->data = subareaList;
cprintf("初始化完成!",CYAN);
printf("主存区大小为:%d,分区个数:%d,最大空闲分区长度为:%d\n",mainStorage->size,mainStorage->subareaCount,getMaxIdleSubarea()->len);
inited = 1;
}
void showMainStorage(){
if(!inited){
cprintfln("请先初始化主存区!",L_RED);
return;
}
subareaNode* subareas = mainStorage->data;
cprintf("\n开始打印主存区表 □ 表示空闲",CYAN);
cprintfln(" ■ 表示正在使用\n\n",L_RED);
while (subareas!=NULL)
{
cprintf("┃",WHITE);
printf("<%d>",subareas->saddr);
for (size_t i = 0; i < subareas->len; i++)
{
if (subareas->flag)
{
cprintf("■ ",L_RED);
}else{
cprintf("□ ",CYAN);
}
}
subareas = subareas->next;
}
cprintf("\n\n主存区打印结束!",CYAN);
printf("主存区大小为:%d,分区个数:%d,最大空闲分区长度为:%d\n",mainStorage->size,mainStorage->subareaCount,getMaxIdleSubarea()->len);
printf("\n\n");
}
//加入作业
void admeasure(job *njob){
string jname = string(njob->name);
subareaNode* oldSubarea = mainStorage->data,*tsubarea;
int flag = 0,dis = mainStorage->size;
while (oldSubarea!=NULL)
{
if(oldSubarea->len >= njob->len && !oldSubarea->flag){//要获取最优适应分区 不重排list的话 就遍历比较了
flag = 1;
if(oldSubarea->len - njob->len == 0){//刚好装得下 直接取第一个就好
tsubarea = oldSubarea;
break;
}
if(oldSubarea->len - njob->len < dis){
dis = oldSubarea->len - njob->len;
tsubarea = oldSubarea;
}
}
oldSubarea = oldSubarea->next;
}
if(!flag){
cprintfln("内存不足,已加入等待队列中(零散分区太多?)!请尝试释放一些内存,或者扩大主存!",L_RED);
waitJobList.push_back(*njob);//加入等待队列
return;
}
subareaNode* jobSubarea = (subareaNode*)malloc(sizeof(subareaNode));//给作业建立分区
jobSubarea->flag = BUSY;
jobSubarea->saddr = njob->saddr = tsubarea->saddr;
jobSubarea->len = njob->len;
mainStorage->subareaCount++;
if(tsubarea->prev==NULL){//主存区表头
mainStorage->data = jobSubarea;
}else
{
tsubarea->prev->next = jobSubarea;
jobSubarea->prev = tsubarea->prev;
}
if(tsubarea->len>jobSubarea->len){//空闲分区长度大于作业所需长度
subareaNode* surplusSubarea = (subareaNode*)malloc(sizeof(subareaNode));//给剩余空闲内存建立分区
surplusSubarea->flag = IDLE;
surplusSubarea->len = tsubarea->len - jobSubarea->len;
surplusSubarea->saddr = jobSubarea->saddr + jobSubarea->len;
jobSubarea->next = surplusSubarea;
surplusSubarea->prev = jobSubarea;
surplusSubarea->next = tsubarea->next;
if(tsubarea->next!=NULL){//主存区表头
tsubarea->next->prev = surplusSubarea;
}
}else{//不然就是刚好等于了.
jobSubarea->prev = NULL;
jobSubarea->next = tsubarea->next;
}
jobMap[jname] = *njob;
}
void tryAdmeasure(){
if(!inited){
cprintfln("请先初始化主存区!",L_RED);
return;
}
job *njob = (job*)malloc(sizeof(job));
cprintf("请输入作业名称:",CYAN);
cin >> njob->name;
string jname = string(njob->name);
map<string,job>::iterator tjobIter = jobMap.find(jname);
list<job>::iterator tjoblistIter;
for (tjoblistIter = waitJobList.begin(); tjoblistIter != waitJobList.end() ;tjoblistIter++)
{
if(string(tjoblistIter->name) == string(njob->name)){
cprintfln("该作业正在等待队列中等待运行!",L_RED);
return;
}
}
if(tjobIter!=jobMap.end()){
cprintfln("该作业名已存在且正在运行!",L_RED);
return;
}
cprintf("请输入作业大小(长度):",CYAN);
cin >> njob->len;
admeasure(njob);
}
void release(){
if(!inited){
cprintfln("请先初始化主存区!",L_RED);
return;
}
char name[100];
cprintf("请输入要删除的作业名称:",CYAN);
cin >> name;
string tname = string(name);
map<string,job>::iterator tjobIter = jobMap.find(tname);
if(tjobIter!=jobMap.end()){
subareaNode* subareas = mainStorage->data;
while (subareas!=NULL)
{
if(tjobIter->second.saddr == subareas->saddr){
if(subareas->prev!=NULL){ //实现释放后自动合并相邻处于空闲状态的分区
if(subareas->prev->flag == IDLE){
subareas->prev->len += subareas->len;
subareas->prev->next = subareas->next;
}
}
if(subareas->next!=NULL){
if(subareas->next->flag == IDLE){
subareas->len += subareas->next->len;
subareas->next = subareas->next->next;
}
}
subareas->flag = IDLE;
jobMap.erase(tname);
mainStorage->subareaCount--;
cprintfln("删除成功!开始通知等待作业队列",L_RED);
list<job>::iterator iter;
for(iter = waitJobList.begin(); iter != waitJobList.end() ;iter++)
{
if(getMaxIdleSubarea()->len >= iter->len){
job *tjob = (job*)malloc(sizeof(job));
tjob->len = iter->len;
strcpy(tjob->name,iter->name);
tjob->saddr = iter->saddr;
admeasure(tjob);
waitJobList.remove(*iter);
cprintf("作业等待队列中的 ",CYAN);
printf("%s",tjob->name);
cprintf(" 已开始运行!\n\n",CYAN);
printf("当前作业等待队列等待个数为:%d\n\n",(int)waitJobList.size());
break;
}
}
break;
}
subareas = subareas->next;
}
}else{
cprintfln("不存在该作业!",L_RED);
}
}
int main(){
PCOLOR = 1;//是否使用颜色 出现乱码就改为0
cprintf("\n▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓\n", CYAN);
cprintf("▓▓ ▓▓\n", CYAN);
cprintf("▓▓ 动态多分区存储管理模拟系统 ▓▓\n", CYAN);
cprintf("▓▓ 最佳适应算法 ▓▓\n", CYAN);
cprintf("▓▓ ▓▓\n", CYAN);
cprintf("▓▓ 1.初始化 ▓▓\n", CYAN);
cprintf("▓▓ 2.显示主存使用情况 ▓▓\n", CYAN);
cprintf("▓▓ 3.模拟分配 ▓▓\n", CYAN);
cprintf("▓▓ 4.模拟回收 ▓▓\n", CYAN);
cprintf("▓▓ 0.退出 ▓▓\n", CYAN);
cprintf("▓▓ ▓▓\n", CYAN);
cprintf("▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓\n", CYAN);
int selectFlag = 0;
while (!exitFlag)
{
cprintf("\n请选择功能:",CYAN);
cin >> selectFlag;
switch (selectFlag)
{
case 1:
init();
break;
case 2:
showMainStorage();
break;
case 3:
tryAdmeasure();
break;
case 4:
release();
break;
case 0:
exitFlag=1;
break;
default:
cprintfln("输入错误!",L_RED);
sleep(1);
break;
}
}
return 0;
}
pro_printf.cpp
#include <stdio.h>
#define NONE "\e[0m"
#define BLACK "\e[0;30m"
#define L_BLACK "\e[1;30m"
#define RED "\e[0;31m"
#define L_RED "\e[1;31m"
#define GREEN "\e[0;32m"
#define L_GREEN "\e[1;32m"
#define BROWN "\e[0;33m"
#define YELLOW "\e[1;33m"
#define BLUE "\e[0;34m"
#define L_BLUE "\e[1;34m"
#define PURPLE "\e[0;35m"
#define L_PURPLE "\e[1;35m"
#define CYAN "\e[0;36m"
#define L_CYAN "\e[1;36m"
#define GRAY "\e[0;37m"
#define WHITE "\e[1;37m"
#define BOLD "\e[1m"
#define UNDERLINE "\e[4m"
#define BLINK "\e[5m"
#define REVERSE "\e[7m"
#define HIDE "\e[8m"
#define CLEAR "\e[2J"
#define CLRLINE "\r\e[K" //or "\e[1K\r"
int PCOLOR = 1;
void cprintf(char* msg,const char* color){
if(PCOLOR)
printf("%s",color);
printf("%s",msg);
if(PCOLOR)
printf("\033[0m");
}
void cprintfln(char* msg,const char* color){
if(PCOLOR)
printf("%s",color);
printf("%s",msg);
if(PCOLOR)
printf("\033[0m\n");
}