This is someone else's code, but I changed most of the content and structure, so that its storage operations all use chained queues. There are some flaws in the original code, but I didn't optimize it for some reasons, but I finished the class all requirements set.
#include <stdio.h>
#include "string.h"
#include "stdlib.h"
typedef struct PCB {
//结构体
char name; // 进程名称(输入)
int arrivetime; //到达时间 (输入)
int running_time; //服务时间
int start_time; //开始时间
int done_time; //结束时间
int copyRunning_time; //用于时间片轮转
float zztime; //记录该进程的周转时间
float dqzztime; //记录该进程的带权周转时间
struct PCB *next; //定义一个指针指向下一个进程
} PCB;
typedef struct PCBQueue {
//结构体
PCB *firstProg;
PCB *LastProg;
int size;
} PCBQueue;
PCB *tempPCB;
// 函数声明
void inputPCB(PCBQueue *queue, int num); //输入所有进程的具体信息
void PrintRunningPCB(PCB *pro);//输出正在运行的进程的信息
void PrintSortOfRunningPCB(PCBQueue *queue);//输出进程的运行顺序
void CopyPCB(PCB *pro1, PCB *pro2);//将进程pro2的信息复制到进程pro1中
void Queueinit(PCBQueue *queue);//初始化就绪队列
void EnterQueue(PCBQueue *queue, PCB *pro);//将一个进程插入到就绪队列中
PCB *poll(PCBQueue *queue);//将一个进程从就绪队列中删除
void sortWithEnterTime(PCBQueue *queue);//将所有进程按到达时间升序排序
//队列Copy
void CopyQueue(PCBQueue *srcQueue, PCBQueue *dstQueue);
void FCFS(PCBQueue *myQueue, int num);//先来先服务调度算法
void RR(PCBQueue *sortQueue);//时间片轮转调度算法
PCB *peek(PCBQueue *queue);
void inputPCB(PCBQueue *queue, int num) {
int i, a, b, c;
for (i = 0; i < num; i++) {
printf("\t\t\t\t\t请输入进程的名字,到达时间,服务时间\n\t\t\t\t\t");
PCB *prog = (PCB *) malloc(sizeof(PCB));
getchar();
scanf_s("%c", &prog->name); // Note the space before %c to consume any leading whitespace
scanf_s("%d:%d:%d", &a, &b, &c);
prog->arrivetime = a * 3600 + b * 60 + c;
scanf_s("%d", &prog->running_time);
prog->copyRunning_time = prog->running_time;
EnterQueue(queue, prog);
}
}
void PrintRunningPCB(PCB *pro) {
printf("\t正在执行》》》进程%c\n", pro->name);
printf("\t————————————————————————————————————————————————\n");
printf("\t进程名字 到达时间 服务时间 开始时间 结束时间 周转时间 带权周转时间\n");
printf("\t%4c%8d:%02d:%02d %d", pro->name, (pro->arrivetime / 3600), ((pro->arrivetime % 3600) / 60),
((pro->arrivetime % 3600) % 60), pro->running_time);
printf("%8d:%02d:%02d %d:%02d:%02d %4.2f %3.2f\n", (pro->start_time / 3600),
((pro->start_time % 3600) / 60), ((pro->start_time % 3600) % 60), (pro->done_time / 3600),
((pro->done_time % 3600) / 60), ((pro->done_time % 3600) % 60), pro->zztime, pro->dqzztime);
printf("\t————————————————————————————————————————————————\n\n");
}
void PrintReadyqueue(PCBQueue *ready_queue) {
PCB *p;
p = ready_queue->firstProg->next;
if (!p) {
printf("\t无进程处于就绪状态!\n");
printf("\t————————————————————————————————————————————————\n\n\n");
return;
}
printf("\t就绪队列:\n");
printf("\t————————————————————————————————————————————————\n");
printf("\t进程名字 到达时间 服务时间\n");
while (p) {
printf("\t%c\t%d:%02d:02%d %d\t", p->name, (p->arrivetime / 3600), ((p->arrivetime % 3600) / 60),
((p->arrivetime % 3600) % 60), p->running_time);
p = p->next;
}
printf("\t————————————————————————————————————————————————\n");
printf("\n\n\n");
}
void PrintSortOfRunningPCB(PCBQueue *queue) {
printf("\t进程运行顺序如下:\n");
printf("\t————————————————————————————————————————————————\n");
printf("\t进程名字 到达时间 服务时间 开始时间 结束时间 周转时间 带权周转时间\n");
while (queue->size > 0) {
tempPCB = poll(queue);
printf("\t%c %8d:%02d:%02d %d", tempPCB->name, (tempPCB->arrivetime / 3600),
((tempPCB->arrivetime % 3600) / 60), ((tempPCB->arrivetime % 3600) % 60), tempPCB->copyRunning_time);
printf("%8d:%02d:%02d %d:%02d:%02d %4.2f %3.2f\n", (tempPCB->start_time / 3600),
((tempPCB->start_time % 3600) / 60), ((tempPCB->start_time % 3600) % 60), (tempPCB->done_time / 3600),
((tempPCB->done_time % 3600) / 60), ((tempPCB->done_time % 3600) % 60), tempPCB->zztime,
tempPCB->dqzztime);
}
printf("\t————————————————————————————————————————————————\n\n\n");
}
//队列初始化
void Queueinit(PCBQueue *queue) {
queue->size = 0;
queue->LastProg = (PCB *) malloc(sizeof(PCB));
queue->LastProg->next = NULL;
queue->firstProg = queue->LastProg;
}
PCB *peek(PCBQueue *queue) {
if (queue->size == 0) {
// 队列为空
printf("队列为空\n");
}
// 返回队列的第一个进程节点
return queue->firstProg->next;
}
void EnterQueue(PCBQueue *queue, PCB *pro) {
//加入进程队列
PCB *newNode = malloc(sizeof(PCB));
newNode->arrivetime = pro->arrivetime;
newNode->done_time = pro->done_time;
newNode->name = pro->name;
newNode->running_time = pro->running_time;
newNode->copyRunning_time = pro->copyRunning_time;
newNode->start_time = pro->start_time;
newNode->zztime = pro->zztime;
newNode->dqzztime = pro->dqzztime;
newNode->next = NULL;
if (queue->LastProg == NULL) {
//如果队列为空,则将新流程节点作为第一个和最后一个节点
queue->firstProg = newNode;
queue->LastProg = newNode;
} else {
// 将新节点附加到队列的末尾
queue->LastProg->next = newNode;
queue->LastProg = newNode;
}
//增加队列大小
queue->size++;
}
//删除队头进程
PCB *poll(PCBQueue *queue) {
//创建一个临时指针变量 temp,用于保存要取出的进程节点
PCB *temp;
//将 temp 指向就绪队列的第一个进程节点的下一个节点,即要取出的进程节点
temp = queue->firstProg->next;
//如果取出的进程节点是就绪队列的最后一个节点
if (temp == queue->LastProg) {
//将就绪队列的最后一个节点指针指向就绪队列的第一个节点,表示就绪队列中没有其他节点
queue->LastProg = queue->firstProg;
//将就绪队列的最后一个节点的下一个指针设置为 NULL,表示就绪队列为空
queue->LastProg->next = NULL;
//就绪队列数量进程减一,表示取出了一个进程节点
queue->size--;
//返回取出的进程节点
return temp;
}
//将第一个进程删除 //将就绪队列的第一个进程节点的下一个指针指向取出的进程节点的下一个节点,即将取出的进程节点从就绪队列中移除
queue->firstProg->next = queue->firstProg->next->next;
//将就绪队列的大小减1,表示取出了一个进程节点
queue->size--;
return temp;
}
//插入排序法
void sortWithEnterTime(PCBQueue *queue) {
PCB *current = queue->firstProg->next;
while (current != NULL) {
PCB *temp = current;
while (temp->next != NULL && temp->next->arrivetime < temp->arrivetime) {
//交换temp和temp->next的位置
PCB *nextProg = temp->next;
temp->next = nextProg->next;
nextProg->next = temp;
if (temp == queue->firstProg)
queue->firstProg = nextProg;
else {
PCB *prev = queue->firstProg;
while (prev->next != temp) prev = prev->next;
prev->next = nextProg;
}
temp = nextProg;
}
current = current->next;
}
}
void FCFS(PCBQueue *sortQueue, int num) {
int time, done_time;
int i, count, tt, pcbNum;
float sum_T_time, sum_QT_time;
PCB *curpro, *temp_PCB;
printf("\n\t\t\t\t\t先来先服务算法进程调度模拟\n\n");
count = 0;//计数器
PCBQueue *complateQueue = malloc(sizeof(PCBQueue));
Queueinit(complateQueue);
//按照进入到达时间顺序排序
sortWithEnterTime(sortQueue);
PCBQueue *queue = (PCBQueue *) malloc(sizeof(PCBQueue));
//就绪队列初始化
Queueinit(queue);
curpro = poll(sortQueue);
//将第一个进程送入就绪队列中
EnterQueue(queue, curpro);
//记录第一个进程的到达时间
time = curpro->arrivetime;
//记录当前的进程数量
pcbNum = 1;
// sum_T_time 记录总的周转时间 ,sum_QT_time 记录总的加权周转时间
sum_T_time = 0, sum_QT_time = 0;
// 当进程队列不为空时循环执行以下操作
while (queue->size > 0) {
// 从进程队列中取出一个进程作为当前执行的进程
curpro = poll(queue);
if (time < curpro->arrivetime) {
// 如果当前时间小于当前进程的到达时间——将当前时间更新为当前进程的到达时
time = curpro->arrivetime;
}
//计算done_time为该进程的结束时间(开始时间+CPU运行时间)
curpro->done_time = time + curpro->running_time;
// 将当前进程的开始时间设为当前时间
curpro->start_time = time;
// 将当前进程的结束时间设为计算得到的结束时间
curpro->done_time = curpro->done_time;
//周转时间
curpro->zztime = curpro->done_time - curpro->arrivetime;
//带权周转时间
curpro->dqzztime = curpro->zztime / curpro->running_time;
// sum_T_time 总的周转时间更新
sum_T_time += curpro->zztime;
// sum_T_time 总的带权周转时间更新
sum_QT_time += curpro->dqzztime;
//模拟进程的执行过程
for (tt = time; tt <= curpro->done_time && pcbNum < num; tt++) {
// 如果当前时间大于等于下一个进程的到达时间,则将下一个进程加入就绪队列
if (tt >= peek(sortQueue)->arrivetime) {
// 将下一个进程加入就绪队列
EnterQueue(queue, poll(sortQueue));
// 进程数量加1
pcbNum++;
}
}
EnterQueue(complateQueue, curpro);
// 打印当前正在执行的进程的信息
PrintRunningPCB(curpro);
count++;
// 如果就绪队列不为空
if (queue->size != 0) {
printf("\t就绪队列:\n");
printf("\t————————————————————————————————————————————————\n");
printf("\t进程 到达时间 服务时间\n");
temp_PCB = queue->firstProg->next;
for (i = queue->size; i > 0; i--) {
printf("\t%c\t%d:%02d:02%d\t%d\t\n", temp_PCB->name, (temp_PCB->arrivetime / 3600),
((temp_PCB->arrivetime % 3600) / 60), ((temp_PCB->arrivetime % 3600) % 60),
temp_PCB->running_time);
temp_PCB = temp_PCB->next;
}
printf("\t————————————————————————————————————————————————\n");
printf("\n\n\n");
} else {
printf("\t无进程处于就绪状态!\n");
printf("\t————————————————————————————————————————————————\n\n\n");
}
// 更新当前时间为当前进程执行完后的时间
time += curpro->running_time;
// 如果就绪队列为空且还有进程未加入队列
if (queue->size == 0 && pcbNum < num) {
//防止出现前一个进程执行完到下一个进程到达之间无进程进入——将下一个进程加入就绪队列
EnterQueue(queue, poll(sortQueue));
pcbNum++;
}
}
// 打印进程执行顺序
PrintSortOfRunningPCB(complateQueue);
printf("\t平均周转时间为:%.2f\n", sum_T_time / num);
printf("\t平均带权周转时间为:%.2f\n", sum_QT_time / num);
}
void RR(PCBQueue *sortQueue) {
int num = sortQueue->size;
int time;
int i, count, tt, timeSlice, pcbNum;
float sum_T_time, sum_QT_time;
PCB *curpro, *temp_PCB;
PCBQueue *myQueue = malloc(sizeof(PCBQueue));
Queueinit(myQueue);
printf("\n\t\t\t\t\t时间片轮转算法进程调度模拟\n\n");
printf("\t————————————————————————————————————————————————\n");
count = 0;
PCBQueue *complateQueue = malloc(sizeof(PCBQueue));
Queueinit(complateQueue);
printf("\t请输入时间片大小:");
scanf("%d", &timeSlice);
sortWithEnterTime(sortQueue);
PCBQueue *queue = malloc(sizeof(PCBQueue));
Queueinit(queue);
peek(sortQueue)->start_time = peek(sortQueue)->arrivetime;
EnterQueue(queue, poll(sortQueue));
time = 0;
pcbNum = 1;
sum_T_time = 0;
sum_QT_time = 0;
while (queue->size > 0) {
curpro = poll(queue);
EnterQueue(myQueue, curpro);
if (time < curpro->arrivetime) {
time = curpro->arrivetime;
}
if (timeSlice >= curpro->running_time) {
for (tt = time; tt <= time + timeSlice && pcbNum < num; tt++) {
if (tt >= peek(sortQueue)->arrivetime) {
peek(sortQueue)->start_time = tt;
EnterQueue(queue, poll(sortQueue));
pcbNum++;
}
}
time += curpro->running_time;
curpro->running_time = 0;
curpro->done_time = time;
curpro->zztime = curpro->done_time - curpro->start_time;
curpro->dqzztime = curpro->zztime / (curpro->copyRunning_time + 0.0);
sum_T_time += curpro->zztime;
sum_QT_time += curpro->dqzztime;
EnterQueue(complateQueue, curpro);
count++;
printf("\n\t执行完成》》》进程%c!\n", curpro->name);
printf("\t————————————————————————————————————————————————\n");
if (queue->size != 0) {
printf("\t就绪队列:\n");
printf("\t————————————————————————————————————————————————\n");
printf("\t进程 到达时间 服务时间\n");
temp_PCB = queue->firstProg->next;
for (i = queue->size; i > 0; i--) {
printf("\t%c\t%d:%02d:%02d\t%d\t\n", temp_PCB->name, (temp_PCB->arrivetime / 3600),
((temp_PCB->arrivetime % 3600) / 60), ((temp_PCB->arrivetime % 3600) % 60),
temp_PCB->running_time);
temp_PCB = temp_PCB->next;
}
printf("\t————————————————————————————————————————————————\n\n\n");
} else {
printf("\t 无进程处于就绪状态!\n");
printf("\t————————————————————————————————————————————————\n\n\n");
}
if (queue->size == 0 && count < num) {
peek(sortQueue)->start_time = peek(sortQueue)->arrivetime;
EnterQueue(queue, poll(sortQueue));
pcbNum++;
}
continue;
}
//判断是否有新的进程在这个时间片执行期间会到达
for (tt = time; tt <= time + timeSlice && pcbNum < num; tt++) {
if (tt >= peek(sortQueue)->arrivetime) {
peek(sortQueue)->start_time = tt;
EnterQueue(queue, poll(sortQueue));
pcbNum++;
}
}
printf("\n\t正在执行》》》进程%c\n", curpro->name);
printf("\t————————————————————————————————————————————————\n");
if (queue->size != 0) {
printf("\t就绪队列:\n");
printf("\t————————————————————————————————————————————————\n");
printf("\t进程 到达时间 服务时间\n");
temp_PCB = queue->firstProg->next;
for (i = queue->size; i > 0; i--) {
printf("\t%c\t%d:%02d:%02d\t%d\t\n", temp_PCB->name, (temp_PCB->arrivetime / 3600),
((temp_PCB->arrivetime % 3600) / 60), ((temp_PCB->arrivetime % 3600) % 60),
temp_PCB->running_time);
temp_PCB = temp_PCB->next;
}
printf("\t————————————————————————————————————————————————\n\n\n");
} else {
printf("\t 无进程处于就绪状态!\n");
printf("\t————————————————————————————————————————————————\n\n\n");
}
time += timeSlice;
curpro->running_time -= timeSlice;
EnterQueue(queue, curpro);
if (queue->size == 0 && pcbNum < sortQueue->size) {
peek(sortQueue)->start_time = peek(sortQueue)->arrivetime;
EnterQueue(queue, poll(sortQueue));
pcbNum++;
}
}
//打印完成顺序
PrintSortOfRunningPCB(complateQueue);
printf("\t平均周转时间为:%.2f\n", sum_T_time / num);
printf("\t平均带权周转时间为:%.2f\n", sum_QT_time / num);
//打印调度顺序
printf("调度序列:\n");
while (myQueue->size > 0) {
temp_PCB = poll(myQueue);
printf("%c -> ", temp_PCB->name);
}
printf("\n");
// 释放内存
free(myQueue);
free(complateQueue);
free(queue);
}
void CopyPCB(PCB *pro1, PCB *pro2) {
pro1->arrivetime = pro2->arrivetime;
pro1->running_time = pro2->running_time;
pro1->start_time = pro2->start_time;
pro1->done_time = pro2->done_time;
pro1->copyRunning_time = pro2->copyRunning_time;
pro1->zztime = pro2->zztime;
pro1->dqzztime = pro2->dqzztime;
pro1->name = pro2->name;
pro1->next = NULL;
}
void CopyQueue(PCBQueue *srcQueue, PCBQueue *dstQueue) {
PCB *curr = srcQueue->firstProg->next;
PCB *newPCB;
while (curr != NULL) {
newPCB = malloc(sizeof(PCB));
CopyPCB(newPCB, curr);
EnterQueue(dstQueue, newPCB);
curr = curr->next;
}
}
void menu() {
printf("\t\t\t\t\t<<-------------操作系统进程调度算法模拟程序----------——>>\n");
printf("\t\t\t\t\t1->先来先服务算法\n");
printf("\t\t\t\t\t2->时间片轮转算法\n");
printf("\t\t\t\t\t3->退出\n");
printf("\t\t\t\t\t请选择:");
}
int main() {
int n, t = 1;
int pcbNum, choice;
PCBQueue *queue = malloc(sizeof(PCBQueue));
PCBQueue *tempQueue = malloc(sizeof(PCBQueue));
Queueinit(queue);
printf("\t\t\t\t\t第5组\n");
printf("\t\t\t\t\t学号姓名\n");
printf("\t\t\t\t\t学号姓名\n");
printf("\t\t\t\t\t请输入进程的个数:");
scanf("%d", &pcbNum);
inputPCB(queue, pcbNum);
while (t) {
menu();
Queueinit(tempQueue); // 初始化临时队列
// 复制队列到临时队列
CopyQueue(queue, tempQueue);
scanf("%d", &n);
while (n <= 0 || n > 5) {
printf("\t\t\t指令不正确,请重新输入指令:");
getchar();
scanf("%d", &n);
}
switch (n) {
case 1: {
FCFS(tempQueue, pcbNum);
break;
}
case 2: {
RR(tempQueue);
break;
}
case 3: {
t = 0;
break;
}
}
}
printf("\n\n\t\t\t\t\t您已成功退出系统!!!\n");
free(queue); // 释放队列内存
free(tempQueue); // 释放临时队列内存
return 0;
}
/**
A 8:00:00 3
B 8:00:02 6
C 8:00:04 4
D 8:00:06 5
E 8:00:08 2
*/