实现以下要求:
- 有录入界面,动态录入进程个数、时间片大小、创建进程控制块(PCB)通过录入界面录入进程标识符、进程到达时间、服务时间等信息;
- 有算法选择界面,能够根据需要选择不同调度算法;
- 有输出界面,能够输出不同调度算法下诸进程的进程标识符、到达时间、服务时间、开始时间、完成时间、周转时间、带权周转时间以及一批作业的平均周转时间、平均带权周转时间;进程调度算法
一、源码
#include<iostream>
#include<assert.h>
#include <map>
using namespace std;
typedef struct PCB
{
char name[10];//此为进程id
char state; //进程状态w/r
int Arrivetime;//进程到达时间
int BeginTime;//进程开始时间
int FinishTime;//进程结束时间
int ServerTime;//进程服务时间
float wholeTime;//周转时间
float Weight_wholetime;//带权周转时间
double Average_wholeTime;//平均周转时间
double Average_weight_wholetime;//带权平均周转时间
int RunTime;//已经占用cpu时间
int NeedTime;//还需要cpu时间
int Prio;//优先级
struct PCB* next;
}pcb, * Pcb;
int Proc_Num = 0;//进程数目
void head_Show(Pcb proc)//输入打印
{
assert(proc != NULL);
printf(" PCB_ID 优先级数 到达时间 服务时间\n");
while (proc != NULL)
{
printf("%6s %6d %6d %6d\n",
proc->name, proc->Prio,
proc->Arrivetime, proc->ServerTime);
proc = proc->next;
}
}
void Show(Pcb proc)
{
assert(proc != NULL);
double sum_wholeTime = 0;
double sum_weight_wholetime = 0;
pcb* p = proc;
while (p != NULL)
{
sum_wholeTime += p->wholeTime;
sum_weight_wholetime += p->Weight_wholetime;
p = p->next;
}
double Average_wholeTim = sum_wholeTime / Proc_Num;
double Average_weight_wholetime = sum_weight_wholetime / Proc_Num;
printf(" PCB_ID 到达时间 开始时间 服务时间 完成时间 周转时间 带权周转时间\n");
while (proc != NULL)
{
printf("%6s %6d %6d %6d %6d %8.1f %8.2f\n",
proc->name,
proc->Arrivetime, proc->BeginTime, proc->ServerTime,
proc->FinishTime, proc->wholeTime, proc->Weight_wholetime);
proc = proc->next;
}
printf(" 平均周转时间 平均带权周转时间 \n");
printf(" %10.2f %10.2f\n", Average_wholeTim,
Average_weight_wholetime);
}
//创建输入链表——不带头结点的单链表
Pcb PCB_Create()
{
cout << "请输入进程个数:";
cin >> Proc_Num;
pcb* _head = NULL;
pcb* _tail = NULL;
if (Proc_Num > 6000)
{
return NULL;
}
cout << "请输入PCB名称、优先级、到达时间、服务时间" << endl;
for (int i = 1; i <= Proc_Num; i++)
{
pcb* new_proc = (pcb*)malloc(sizeof(pcb));
assert(NULL != new_proc);
cin >> new_proc->name >> new_proc->Prio >> new_proc->Arrivetime >> new_proc->ServerTime;
new_proc->next = NULL;
new_proc->NeedTime = new_proc->ServerTime;
new_proc->RunTime = 0;
new_proc->BeginTime = 0;
new_proc->FinishTime = 0;
if (NULL == _head)
{
_tail = new_proc;
_head = new_proc;
}
else
{
_tail->next = new_proc;
_tail = new_proc;
}
}
return _head;
}
//时间先后顺序排序
Pcb Sort_Arrivetime(Pcb list)
{
assert(NULL != list);
pcb* new_head = (pcb*)malloc(sizeof(pcb));
assert(NULL != new_head);
new_head->Arrivetime = 0;
new_head->ServerTime = 0;
new_head->next = NULL;
pcb* head = NULL;
while (list != NULL)
{
pcb* cur = list; //指向当前进程
list = list->next;
cur->next = NULL;
if (new_head->next == NULL)
{
new_head->next = cur;
}
else
{
pcb* ptr = new_head;
//ptr 移动到指向最后一个进程
for (ptr; ptr->next != nullptr; ptr = ptr->next);
//当前进程进入时间大,直接接到最后一个的下一个
if (cur->Arrivetime >= ptr->Arrivetime)
{
ptr->next = cur;
}
else
{
pcb* p = new_head;
//p从进程链表里从头遍历,找到当前进程进入时间较已在链表中进程进入时间小的位置
while (cur->Arrivetime > p->next->Arrivetime)
{
p = p->next;
}
//插入当前进程
cur->next = p->next;
p->next = cur;
}
}
}
return new_head->next;
}
//短作业排序链表
Pcb Sort_Shortjob(Pcb list)
{
assert(NULL != list);
pcb* new_head = (pcb*)malloc(sizeof(pcb));
assert(NULL != new_head);
new_head->Arrivetime = 0;
new_head->ServerTime = 0;
new_head->next = NULL;
pcb* head = NULL;
while (list != NULL)
{
pcb* cur = list;
list = list->next;
cur->next = NULL;
if (new_head->next == NULL)
{
new_head->next = cur;
}
else
{
pcb* ptr = new_head;
for (ptr; ptr->next != nullptr; ptr = ptr->next);
if (cur->ServerTime >= ptr->ServerTime)
{
ptr->next = cur;
}
else
{
pcb* p = new_head;
while (cur->ServerTime > p->next->ServerTime)
{
p = p->next;
}
cur->next = p->next;
p->next = cur;
}
}
}
return new_head;
}
PCB* RR_runprocces(PCB* head, int time_slice)//时间片轮转
{
assert(head != nullptr);
int _time = head->Arrivetime;
int flag = 0; //记录未完成的进程数量
bool tag = false; //表示未被释放,需要放到链尾
map<char*, int> mp;
for (pcb* p = head; p != NULL; p = p->next)
{
flag++;
mp.insert (make_pair(p->name, 0));
}
//head 为未执行的进程链表
//新建执行链表 run_head, 不带头结点
//初始状态只有按进入时间排好的第一个进程
pcb* run_head = head;
head = head->next;
run_head->next = nullptr;
//新建执行完毕链表 runed_head, 不带头结点
pcb* runed_head = nullptr;
while (flag > 0)
{
if (run_head == nullptr) //执行链表中的都执行完毕,但还有进程未到
{
run_head = head;
head = head->next;
run_head->next = nullptr;
_time = run_head->Arrivetime;
}
pcb* ptr = run_head;
cout << _time << "时刻" << "开始执行: " << ptr->name << endl;
map<char*, int> ::iterator it = mp.find(ptr->name);
if (it != mp.end() && it->second == 0)
{
it->second = 1;
ptr->BeginTime = _time;
}
//运行所需时间小于等于时间片
if (ptr->NeedTime <= time_slice)
{
_time += ptr->NeedTime < time_slice ? ptr->NeedTime : time_slice;
//执行完毕
cout << _time << "时刻" << ptr->name << "执行完毕" << endl;
cout << endl;
flag--;
ptr->state = 'P';
ptr->FinishTime = _time;
//移到已执行完毕链表 或
//直接销毁
pcb* des = run_head;
run_head = run_head->next;
des->next = nullptr;
//free(des);
//des = nullptr;
if (runed_head == nullptr)
{
runed_head = des;
}
else
{
pcb* ped = runed_head;
for (; ped->next != nullptr; ped = ped->next); //ped 指向最后一个进程
ped->next = des;
}
tag = true;
}
else
{ //未执行完毕,时间片结束
_time += time_slice;
//修改该进程的信息
ptr->RunTime += time_slice; //已执行时长
ptr->NeedTime = ptr->ServerTime - ptr->RunTime; //还需CPU时长
if (ptr->NeedTime > 0)
{
cout << "时刻:" << _time<< "\t挂起作业:" << ptr->name;
cout << "\t已运行:" << ptr->RunTime << "\t还需要执行:" << ptr->NeedTime << endl;
cout << endl;
}
}
//遍历未执行进程链表,将当前时间到达的进程放入执行链表
for (head; head != nullptr; )
{
if (head->Arrivetime <= _time)
{
pcb* q = head;
//从原未执行链表移出
head = head->next;
q->next = nullptr;
//采用尾插法放入执行链表
pcb* p = run_head;
if (run_head == nullptr)
run_head = q;
else
{
for (; p->next != nullptr; p = p->next); //p 指向最后一个进程
p->next = q;
}
}
//未执行进程链表是按照到达时间排好的,后面的只会越来越晚
else
break;
}
if (tag == true) //被释放
{
tag = false;
continue;
}
//当前进程挂到执行队列尾
pcb* p = run_head;
for (; p->next != nullptr; p = p->next); //p 指向最后一个进程
pcb* p1 = run_head;
run_head = run_head->next;
p1->next = nullptr;
p->next = p1;
}
//补全周转时间和带权周转时间等
for (pcb* s = runed_head; s != nullptr; s = s->next)
{
s->wholeTime = s->FinishTime - s->Arrivetime;
s->Weight_wholetime = s->wholeTime / s->ServerTime;
}
return runed_head;
}
Pcb End_list(Pcb plist)//最终链表
{
assert(NULL != plist);
int begin_time = plist->Arrivetime; //起始时间为第一个的到达时间
plist->BeginTime = begin_time;
int end_time = begin_time + plist->ServerTime;
plist->FinishTime = end_time;
plist->wholeTime = (float)(plist->FinishTime - plist->Arrivetime);
plist->Weight_wholetime = (float)(plist->wholeTime / plist->ServerTime);
plist->state = 'W';
plist->RunTime = 0;
pcb* ptr = plist->next;
while (ptr != NULL)
{
//上一个进程结束,但下一个未到
if (ptr->Arrivetime > end_time)
{
end_time = ptr->Arrivetime;
}
ptr->BeginTime = end_time;
ptr->FinishTime = end_time + ptr->ServerTime;
end_time += ptr->ServerTime;
ptr->wholeTime = (float)(ptr->FinishTime - ptr->Arrivetime);
ptr->Weight_wholetime = (float)(ptr->wholeTime / ptr->ServerTime);
ptr->state = 'W';
ptr->RunTime = 0;
ptr = ptr->next;
}
return plist;
}
Pcb Sort_SJFjob(Pcb list, int time)
{
assert(NULL != list);
//先按照服务时间进行排序——服务时长链表,带头结点
pcb* ptr_head = Sort_Shortjob(list);
//创建进程已执行链表
pcb* head_node = (pcb*)malloc(sizeof(pcb));
assert(head_node != NULL);
head_node->Arrivetime = 0;
head_node->ServerTime = 0;
head_node->Prio = 0;
head_node->next = NULL;
//链表不为空,表明还有进程未执行
while (ptr_head->next != NULL)
{
//a 指向服务时长链表中第一个进程
pcb* a = ptr_head->next;
if (a->next == NULL) //仅有一个进程,直接放入执行链表
{
//tail 指向进程执行链表的最后一个进程
pcb* tail = head_node;
for (tail; tail->next != NULL; tail = tail->next);
//放入仅剩的一个进程
tail->next = a;
ptr_head->next = NULL;
}
else //服务时长链表中未执行的进程不止一个
{
//找一个进程的进入时间小于当前时间直至最后一个
while (a->Arrivetime > time && a->next != NULL)
{
a = a->next;
}
//所有服务时长链表中未执行的进程在当前时间都为进入
if (a->next == NULL && a->Arrivetime > time)
{
pcb* e = ptr_head->next;
//销毁原按照服务时长排序的链表
ptr_head->next = NULL;
free(ptr_head);
//重新按照到达时间排序,在所有未进入的中选最先进入的
pcb* d = Sort_Arrivetime(e);
// s指向最先进入的进程
pcb* s = d->next;
d->next = NULL;
//变更当前时间
time = time + d->ServerTime;
//将最先进入的进程d,放入进程已执行链表
pcb* tail = head_node;
for (tail; tail->next != NULL; tail = tail->next);
tail->next = d;
//对剩下的再次服务时间排序,为下次按照服务时间放入已执行链表做准备
ptr_head = Sort_Shortjob(s);
}
//在当前时间下,服务时长链表中存在进程到达时间较小,即已经到达,要放入执行链表
else
{
//在服务时长链表找到已经到达的进程a的前驱
pcb* c = ptr_head;
while (c->next != a)
{
c = c->next;
}
//将进程a摘除
c->next = a->next;
a->next = NULL;
//变更当前时间
time = time + a->ServerTime;
//将进程a放到已执行链表
pcb* tail = head_node;
for (tail; tail->next != NULL; tail = tail->next);
tail->next = a;
}
}
}
//返回已执行链表,不带头结点
pcb* back_head = head_node->next;
head_node->next = NULL;
free(head_node);
head_node = NULL;
return back_head;
}
Pcb Sort_SJF(Pcb list)
{
assert(list != NULL);
//首先按照到达时间排好链表(无头结点)
pcb* head = Sort_Arrivetime(list);
int _time = head->Arrivetime;
if (head->next != NULL)
{
pcb* _head = Sort_SJFjob(head, _time);
head = _head;
}
return head;
}
//按优先级排序
Pcb Sort_PRC(Pcb list)
{
assert(NULL != list);
pcb* new_head = (pcb*)malloc(sizeof(pcb));
assert(NULL != new_head);
new_head->Arrivetime = 0;
new_head->ServerTime = 0;
new_head->Prio = 0;
new_head->next = NULL;
pcb* head = NULL;
while (list != NULL)
{
pcb* cur = list;
list = list->next;
cur->next = NULL;
if (new_head->next == NULL)
{
new_head->next = cur;
}
else
{
pcb* ptr = new_head;
for (ptr; ptr->next != nullptr; ptr = ptr->next);
if (ptr->Prio >= cur->Prio)
{
ptr->next = cur;
}
else
{
pcb* p = new_head;
while (p->next->Prio > cur->Prio)
{
p = p->next;
}
cur->next = p->next;
p->next = cur;
}
}
}
return new_head;
}
Pcb Sort_PrcjobNB(Pcb list, int time)
{
assert(NULL != list);
//先按照优先级进行排序——优先级链表,带头结点
pcb* ptr_head = Sort_PRC(list);
//创建进程已执行链表
pcb* head_node = (pcb*)malloc(sizeof(pcb));
assert(head_node != NULL);
head_node->Arrivetime = 0;
head_node->ServerTime = 0;
head_node->Prio = 0;
head_node->next = NULL;
//链表不为空,表明还有进程未执行
while (ptr_head->next != NULL)
{
//a 指向优先级链表中第一个进程
pcb* a = ptr_head->next;
if (a->next == NULL) //仅有一个进程,直接放入执行链表
{
//tail 指向进程执行链表的最后一个进程
pcb* tail = head_node;
for (tail; tail->next != NULL; tail = tail->next);
//放入仅剩的一个进程
tail->next = a;
ptr_head->next = NULL;
}
else //优先级链表中未执行的进程不止一个
{
//找一个进程的进入时间小于当前时间直至最后一个
while (a->Arrivetime > time && a->next != NULL)
{
a = a->next;
}
//所有优先级链表中未执行的进程在当前时间都未进入
if (a->next == NULL && a->Arrivetime > time)
{
pcb* e = ptr_head->next;
//销毁原按照优先级排序的链表
ptr_head->next = NULL;
free(ptr_head);
//重新按照到达时间排序,在所有未进入的中选最先进入的
pcb* d = Sort_Arrivetime(e);
// s指向最先进入的进程
pcb* s = d->next;
d->next = NULL;
//变更当前时间
time = time + d->ServerTime;
//将最先进入的进程d,放入进程已执行链表
pcb* tail = head_node;
for (tail; tail->next != NULL; tail = tail->next);
tail->next = d;
//对剩下的再次优先级排序,为下次按照服务时间放入已执行链表做准备
ptr_head = Sort_PRC(s);
}
//在当前时间下,优先级链表中存在进程到达时间较小,即已经到达,要放入执行链表
else
{
//在优先级链表找到已经到达的进程a的前驱
pcb* c = ptr_head;
while (c->next != a)
{
c = c->next;
}
//将进程a摘除
c->next = a->next;
a->next = NULL;
//变更当前时间
time = time + a->ServerTime;
//将进程a放到已执行链表
pcb* tail = head_node;
for (tail; tail->next != NULL; tail = tail->next);
tail->next = a;
}
}
}
//返回已执行链表,不带头结点
pcb* back_head = head_node->next;
head_node->next = NULL;
free(head_node);
head_node = NULL;
return back_head;
}
Pcb Sort_Prc(Pcb list)
{
assert(list != NULL);
pcb* head = Sort_Arrivetime(list);
int _time = head->Arrivetime;
if (head->next != NULL)
{
head = Sort_PrcjobNB(head, _time);
}
return head;
}
void FCFS()//先来先服务
{
//创建进程队列
pcb* head = PCB_Create();
printf("\t\t算法调度前如下:\n");
head_Show(head);
putchar('\n');
printf("\t\t\t\t算法调度后如下:\n");
//按进程到达时间排序
pcb* end_head = Sort_Arrivetime(head);
struct PCB* list = End_list(end_head);
Show(list);
}
//短作业优先
void SJF()
{
pcb* head = PCB_Create();
printf("\t\t算法调度前如下:\n");
head_Show(head);
putchar('\n');
printf("\t\t\t\t算法调度后如下:\n");
pcb* end = Sort_SJF(head);
pcb* list = End_list(end);
Show(list);
}
//优先级调度
void PrioCreate()
{
pcb* head = PCB_Create();
printf("\t\t算法调度前如下:\n");
head_Show(head);
putchar('\n');
printf("\t\t\t\t算法调度后如下:\n");
pcb* end = Sort_Prc(head);
pcb* list = End_list(end);
Show(list);
}
//时间片轮转算法
void RR()
{
int time_slice;
cout << "输入时间片:";
cin >> time_slice;
pcb* head = PCB_Create();
printf("\t\t算法调度前如下:\n");
head_Show(head);
putchar('\n');
printf("\t\t\t\t算法调度后如下:\n");
pcb* end_head = Sort_Arrivetime(head);
PCB* runed_head = RR_runprocces(end_head, time_slice);
Show(runed_head);
}
int main()
{
int select = 1;
while (select)
{
cout << "******************************************\n";
cout << "*****1.******* 先来先服务算法 ************\n";
cout << "*****2.******** 短作业优先 ************\n";
cout << "*****3.******** 时间片轮转 ************\n";
cout << "*****4.******** 优先级调度 ************\n";
cout << "*****0.**********退出*********************\n";
cout << "请选择:> ";
cin >> select;
switch (select)
{
case 1:
//先来先服务
FCFS();
break;
case 2:
//短作业优先
SJF();
break;
case 3:
//时间片轮转
RR();
break;
case 4:
//优先级调度
PrioCreate();
break;
default:
break;
}
}
return 0;
}
二、测试与执行结果
1、先到先服务:
测试用例:
执行结果:
2、短作业优先算法
测试用例:
执行结果:
3、时间片轮转
测试用例:
执行结果:
4、优先级调度
测试用例:
执行结果:
有问题请联系QQ:1213403737(大牛)
(学妹优先👻)