431 lines
8.9 KiB
C++
431 lines
8.9 KiB
C++
#include<stdio.h>
|
||
#include<stdlib.h>
|
||
#define N 5
|
||
#include<iostream>
|
||
using namespace std;
|
||
enum STATE
|
||
{
|
||
F,W
|
||
};
|
||
|
||
struct subAreaNode
|
||
{
|
||
int addr; // 起始地址
|
||
int size; // 分区大小
|
||
int taskId; // 作业号
|
||
STATE state; // 分区状态
|
||
subAreaNode *pre; // 分区前向指针
|
||
subAreaNode *nxt; // 分区后向指针
|
||
}subHead;
|
||
|
||
|
||
struct PCB
|
||
{
|
||
char name[8]; //进程名
|
||
int arrive_time; //到达时间
|
||
int run_time; //运行时间
|
||
int finish_time; //完成时间
|
||
int zhouzhuan_time; //周转时间
|
||
float daiquan_time; //带权周转时间
|
||
};
|
||
|
||
float sumzhouzhuantime,sumdaiquanzhouzhuantime;
|
||
struct PCB pcb[N],temp;
|
||
|
||
void input(); //输入进程
|
||
void sort(); //对输入的进程按到达时间进行排序执行
|
||
void output(); //输出算法调度时间表
|
||
|
||
|
||
|
||
// 初始化空闲分区链
|
||
void intSubArea()
|
||
{
|
||
// 分配初始分区内存
|
||
subAreaNode *fir = (subAreaNode *)malloc(sizeof(subAreaNode));
|
||
// 给首个分区赋值
|
||
fir->addr = 0;
|
||
fir->size = 1000; // 内存初始大小
|
||
fir->state = F;
|
||
fir->taskId = -1;
|
||
fir->pre = &subHead;
|
||
fir->nxt = NULL;
|
||
// 初始化分区头部信息
|
||
subHead.pre = NULL;
|
||
subHead.nxt = fir;
|
||
}
|
||
|
||
|
||
// 最佳适应算法
|
||
int BestFit(int taskId, int size)
|
||
{
|
||
subAreaNode *tar = NULL;
|
||
int tarSize = 1000 + 1;
|
||
subAreaNode *p = subHead.nxt;
|
||
while (p != NULL)
|
||
{
|
||
// 寻找最佳空闲区间
|
||
if (p->state == F && p->size >= size && p->size < tarSize) {
|
||
tar = p;
|
||
tarSize = p->size;
|
||
}
|
||
p = p->nxt;
|
||
}
|
||
if (tar != NULL) {
|
||
// 找到要分配的空闲分区
|
||
if (tar->size - size <= 10)
|
||
{
|
||
// 整块分配
|
||
tar->state = W;
|
||
tar->taskId = taskId;
|
||
}
|
||
else
|
||
{
|
||
// 分配大小为size的区间
|
||
subAreaNode *node = (subAreaNode *)malloc(sizeof(subAreaNode));
|
||
node->addr = tar->addr + size;
|
||
node->size = tar->size - size;
|
||
node->state = F;
|
||
node->taskId = -1;
|
||
// 修改分区链节点指针
|
||
node->pre = tar;
|
||
node->nxt = tar->nxt;
|
||
if (tar->nxt != NULL)
|
||
{
|
||
tar->nxt->pre = node;
|
||
}
|
||
tar->nxt = node;
|
||
// 分配空闲区间
|
||
tar->size = size;
|
||
tar->state = W;
|
||
tar->taskId = taskId;
|
||
}
|
||
printf("内存分配成功!\n");
|
||
return 1;
|
||
}
|
||
else
|
||
{
|
||
printf("找不到合适的内存分区,分配失败...\n");
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
void BadFit(int taskId,int size){ //最坏适应
|
||
//最佳块指针
|
||
struct subAreaNode *q = NULL;
|
||
subAreaNode *node = subHead.nxt;
|
||
//首先找到第一个满足条件的空闲块
|
||
while(node != NULL){
|
||
if(node->state == F && node->size >= size){
|
||
q = node;
|
||
break;
|
||
}
|
||
//如果下一个为空则说明没有空闲区可以分配
|
||
if(node->nxt == NULL){
|
||
printf("分配失败,没有足够的空间!\n");
|
||
break;
|
||
} else{
|
||
node = node->nxt;
|
||
}
|
||
|
||
}
|
||
//遍历寻找最佳的空闲块
|
||
while(node != NULL){
|
||
if(node->state == F && node->size >= size && node->size < q->size){ //空闲的空间
|
||
q = node;
|
||
}
|
||
node = node->nxt;
|
||
}
|
||
if(q->size < size){ //最佳空闲块的大小小于需求大小
|
||
//分配后剩余的空间
|
||
struct subAreaNode *p = (struct subAreaNode*)malloc(sizeof(struct subAreaNode));
|
||
p->addr = q->addr + size;
|
||
p->size = q->size - size;
|
||
p->state = F;
|
||
p->taskId = -1;
|
||
//分配的空间
|
||
q->taskId = taskId;
|
||
q->size = size;
|
||
q->state = W;
|
||
//改变节点的连接
|
||
p->nxt = q->nxt;
|
||
q->nxt = p;
|
||
}else if(q->size == size){ //最佳空闲块空间大小和需求相等
|
||
q->taskId = taskId;
|
||
q->size = size;
|
||
q->state = W;
|
||
}
|
||
}
|
||
|
||
|
||
int freeSubArea(int taskId) // 回收内存
|
||
{
|
||
int flag = 0;
|
||
subAreaNode *p = subHead.nxt, *pp;
|
||
while (p != NULL)
|
||
{
|
||
if (p->state == W && p->taskId == taskId)
|
||
{
|
||
flag = 1;
|
||
if ((p->pre != &subHead && p->pre->state == F)
|
||
&& (p->nxt != NULL && p->nxt->state == F))
|
||
{
|
||
// 情况1:合并上下两个分区
|
||
// 先合并上区间
|
||
pp = p;
|
||
p = p->pre;
|
||
p->size += pp->size;
|
||
p->nxt = pp->nxt;
|
||
pp->nxt->pre = p;
|
||
free(pp);
|
||
// 后合并下区间
|
||
pp = p->nxt;
|
||
p->size += pp->size;
|
||
p->nxt = pp->nxt;
|
||
if (pp->nxt != NULL)
|
||
{
|
||
pp->nxt->pre = p;
|
||
}
|
||
free(pp);
|
||
}
|
||
else if ((p->pre == &subHead || p->pre->state == W)
|
||
&& (p->nxt != NULL && p->nxt->state == F))
|
||
{
|
||
// 情况2:只合并下面的分区
|
||
pp = p->nxt;
|
||
p->size += pp->size;
|
||
p->state = F;
|
||
p->taskId = -1;
|
||
p->nxt = pp->nxt;
|
||
if (pp->nxt != NULL)
|
||
{
|
||
pp->nxt->pre = p;
|
||
}
|
||
free(pp);
|
||
}
|
||
else if ((p->pre != &subHead && p->pre->state == F)
|
||
&& (p->nxt == NULL || p->nxt->state == W))
|
||
{
|
||
// 情况3:只合并上面的分区
|
||
pp = p;
|
||
p = p->pre;
|
||
p->size += pp->size;
|
||
p->nxt = pp->nxt;
|
||
if (pp->nxt != NULL)
|
||
{
|
||
pp->nxt->pre = p;
|
||
}
|
||
free(pp);
|
||
}
|
||
else
|
||
{
|
||
// 情况4:上下分区均不用合并
|
||
p->state = F;
|
||
p->taskId = -1;
|
||
}
|
||
}
|
||
p = p->nxt;
|
||
}
|
||
if (flag == 1)
|
||
{
|
||
// 回收成功
|
||
printf("内存分区回收成功...\n");
|
||
return 1;
|
||
}
|
||
else
|
||
{
|
||
// 找不到目标作业,回收失败
|
||
printf("找不到目标作业,内存分区回收失败...\n");
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
// 显示空闲分区链情况
|
||
void showSubArea()
|
||
{
|
||
printf("\n");
|
||
printf(" 当前的内存分配情况如下: \n");
|
||
printf(" W:工作状态 F:空闲状态 \n");
|
||
printf("___________________________________________\n");
|
||
printf("| 起始地址 | 空间大小 | 工作状态 | 作业号 |\n");
|
||
subAreaNode *p = subHead.nxt;
|
||
while (p != NULL)
|
||
{
|
||
printf("___________________________________________\n");
|
||
|
||
printf(" %3d k |", p->addr);
|
||
printf(" %3d k |", p->size);
|
||
printf(" %s |", p->state == F ? "F" : "W");
|
||
if (p->taskId > 0)
|
||
{
|
||
printf(" %2d ", p->taskId);
|
||
}
|
||
else
|
||
{
|
||
printf(" ");
|
||
}
|
||
printf("\n");
|
||
p = p->nxt;
|
||
}
|
||
printf("___________________________________________\n");
|
||
}
|
||
|
||
void sort() //按照到达时间对进程进行排序
|
||
{
|
||
for(int i=0;i<N-1;i++)
|
||
{
|
||
for(int j=i+1;j<N;j++)
|
||
{
|
||
if(pcb[i].arrive_time>pcb[j].arrive_time)
|
||
{
|
||
temp=pcb[i];
|
||
pcb[i]=pcb[j];
|
||
pcb[j]=temp;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void output(int j)
|
||
{
|
||
int i;
|
||
cout<<"进程运行信息如下(FCFS调度算法):"<<endl;
|
||
pcb[0].finish_time=pcb[0].arrive_time+pcb[0].run_time;
|
||
pcb[0].zhouzhuan_time=pcb[0].finish_time-pcb[0].arrive_time;
|
||
pcb[0].daiquan_time=(float)pcb[0].zhouzhuan_time/pcb[0].run_time;
|
||
for(i=1;i<j;i++)
|
||
{
|
||
if(pcb[i].arrive_time>pcb[i-1].finish_time)
|
||
{
|
||
pcb[i].finish_time=pcb[i].arrive_time+pcb[i].run_time;
|
||
pcb[i].zhouzhuan_time=pcb[i].run_time;
|
||
pcb[i].daiquan_time=(float)pcb[i].zhouzhuan_time/pcb[i].run_time;
|
||
}
|
||
else
|
||
{
|
||
pcb[i].finish_time=pcb[i-1].finish_time+pcb[i].run_time;
|
||
pcb[i].zhouzhuan_time=pcb[i].finish_time-pcb[i].arrive_time;
|
||
pcb[i].daiquan_time=(float)pcb[i].zhouzhuan_time/pcb[i].run_time;
|
||
}
|
||
|
||
}
|
||
|
||
for(i=0;i<j;i++)
|
||
{
|
||
sumzhouzhuantime+=pcb[i].zhouzhuan_time;
|
||
sumdaiquanzhouzhuantime+=pcb[i].daiquan_time;
|
||
}
|
||
|
||
printf("****************************************************************\n");
|
||
printf("进程名 到达时间 运行时间 完成时间 周转时间 带权周转时间 \n");
|
||
printf("****************************************************************\n");
|
||
for(i=0;i<j;i++)
|
||
{
|
||
printf(" %s %d %d %d %d %.2f\n",pcb[i].name,pcb[i].arrive_time,pcb[i].run_time,pcb[i].finish_time,pcb[i].zhouzhuan_time,pcb[i].daiquan_time);
|
||
|
||
}
|
||
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
|
||
cout<<"平均周转时间:"<<sumzhouzhuantime/N<<endl;
|
||
cout<<"平均带权周转时间:"<<sumdaiquanzhouzhuantime/N<<endl;
|
||
printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
|
||
}
|
||
|
||
|
||
void showProess(int j){
|
||
printf("进程输入信息如下:\n");
|
||
printf("进程名 到达时间 服务时间\n");
|
||
for(int i=0;i<j;i++)
|
||
{
|
||
printf("%s \t",pcb[i].name);
|
||
printf("%d \t",pcb[i].arrive_time);
|
||
printf("%d \n",pcb[i].run_time);
|
||
}
|
||
}
|
||
|
||
int main()
|
||
{
|
||
int ope, taskId, size,select,count;
|
||
//oep 功能选择 taskId 进程号 size 进程大小 select 分配算法选择 count 计数
|
||
|
||
// 初始化空闲分区链
|
||
intSubArea();
|
||
printf(">>>>>>>>>>>>>>>>>>动态分区算法模拟之最佳/最坏适应算法<<<<<<<<<<<<<<<<<<\n") ;
|
||
printf(" ____________________________________\n");
|
||
printf(" | 1: 最佳适应算法 2: 最坏适应算法 |\n");
|
||
printf(" |___________________________________|\n");
|
||
printf("请选择分配算法:");
|
||
scanf("%d",&select);
|
||
|
||
// 模拟动态分区分配算法
|
||
|
||
for(int i=0;i<N;i++){
|
||
printf(" ________________________________________________________________\n");
|
||
printf(" | 1: 分配内存 2: 回收内存 3.分区情况 4.进程信息 0: 退出 |\n");
|
||
printf(" |_______________________________________________________________|\n");
|
||
printf("请选择执行的功能:");
|
||
scanf("%d", &ope);
|
||
if (ope == 0) break;
|
||
if (ope == 1) {
|
||
|
||
// 模拟分配内存
|
||
printf("请输入作业号: ");
|
||
scanf("%d", &taskId);
|
||
|
||
|
||
printf("请输入进程名:" );
|
||
scanf("%s",pcb[i].name);
|
||
printf("请输入到达时间:");
|
||
scanf("%d",&pcb[i].arrive_time);
|
||
printf("请输入要运行时间:");
|
||
scanf("%d",&pcb[i].run_time);
|
||
|
||
printf("请输入需要分配的内存大小(KB): ");
|
||
scanf("%d", &size);
|
||
count+=1;
|
||
// showProess(count);
|
||
|
||
if (size <= 0)
|
||
{
|
||
printf("ERROR:分配内存大小必须为正值\n");
|
||
continue;
|
||
}
|
||
switch(select){ //分配算法选择
|
||
case 1:
|
||
BestFit(taskId,size);
|
||
break ;
|
||
case 2:
|
||
BadFit(taskId,size);
|
||
break ;
|
||
}
|
||
}
|
||
else if (ope == 2)
|
||
{
|
||
// 模拟回收内存
|
||
printf("请输入要回收的作业号: ");
|
||
scanf("%d", &taskId);
|
||
freeSubArea(taskId);
|
||
showSubArea();
|
||
}
|
||
else if(ope==3){
|
||
showSubArea(); // 显示空闲分区链情况
|
||
}
|
||
else if(ope==4){
|
||
showProess(count);
|
||
output(count);
|
||
}
|
||
else
|
||
{
|
||
printf("错误:请输入 0/1/2\n");
|
||
}
|
||
}
|
||
printf("分配算法模拟结束\n");
|
||
system("pause");
|
||
return 0;
|
||
}
|