【歌词】李皓天-胭脂醉

梧桐袅袅羞 一点芭蕉一点愁
爱还未退走 我已迷惘在其中
雨在江面停留 淋湿我无声的等候
散不了的情愁 飘荡了整整一个秋


花近了高楼 一声琵琶一声忧
梦已到尽头 我却不忍向前走
风吹断了扬柳 随着湘水一起北流
千里后再回首 你已在江南烟雨中
奏一曲琵琶泪我白头为了谁
拔银弦声还未起先湿梨花魅
弹不完嘈嘈思念空音无人回
琴头刻我爱无悔 挑出一声催人泪
花近了高楼 一声琵琶一声忧
梦已到尽头 我却不忍向前走
风吹断了扬柳 随着湘水一起北流
千里后再回首 你已在江南烟雨中
奏一曲琵琶泪我白头为了谁
拔银弦声还未起先湿梨花魅
弹不完嘈嘈思念空音无人回
琴头刻我爱无悔 挑出一声催人泪

奏一曲琵琶泪我白头为了谁
拔银弦声还未起先湿梨花魅
弹不完嘈嘈思念空音无人回
琴头刻我爱无悔 挑出一声催人泪
奏一曲琵琶泪我白头为了谁
怎奈是红颜未知却已心先碎
拾不尽萧萧残爱唯有独自悲
而你却与谁依偎 给着你无暇的美
#include <stdio.h> #include <stdlib.h> #include <string.h> // 定义时间结构体,精确到秒 typedef struct { int hour; int minute; int second; } Time; // 进程控制块PCB typedef struct PCB { char name[20]; // 进程名称 Time arrivalTime; // 到达时间 int burstTime; // 运行时间(秒) int remainingTime; // 剩余运行时间(秒),用于RR算法 int startTime; // 开始时间(秒) int completionTime; // 完成时间(秒) int turnaroundTime; // 周转时间 float weightedTurnaroundTime; // 带权周转时间 int waitingTime; // 等待时间 int hasStarted; // 标记进程是否已开始执行 } PCB; // PCB队列 typedef struct { PCB* processes; // 进程数组 int capacity; // 队列容量 int size; // 当前队列大小 } PCBQueue; // 初始化就绪队列 PCBQueue* initQueue(int capacity) { PCBQueue* queue = (PCBQueue*)malloc(sizeof(PCBQueue)); queue->processes = (PCB*)malloc(capacity * sizeof(PCB)); queue->capacity = capacity; queue->size = 0; return queue; } // 将时间转换为总秒数 int timeToSeconds(Time t) { return t.hour * 3600 + t.minute * 60 + t.second; } // 将总秒数转换为时间格式 Time secondsToTime(int seconds) { Time t; t.hour = seconds / 3600; t.minute = (seconds % 3600) / 60; t.second = seconds % 60; return t; } // 入队函数: void enqueue(PCBQueue* queue, PCB process) { if (queue->size >= queue->capacity) { printf("队列已满,无法插入进程\n"); return; } // 找到插入位置,保持到达时间有序 int i; for (i = queue->size; i > 0; i--) { if (timeToSeconds(process.arrivalTime) >= timeToSeconds(queue->processes[i - 1].arrivalTime)) { break;//找到插入位置,将到达时间晚的进程后移。 } queue->processes[i] = queue->processes[i - 1];//将进程插入到合适的位置。 } queue->processes[i] = process; queue->size++; } // 出队函数 PCB dequeue(PCBQueue* queue) //从队列中取出一个进程,按到达时间顺序。 { if (queue->size == 0) { printf("队列为空,无法取出进程\n"); exit(1); } PCB process = queue->processes[0]; // 取出队列的第一个进程。 for (int i = 0; i < queue->size - 1; i++)//将后面的进程前移。 { queue->processes[i] = queue->processes[i + 1]; } queue->size--;//队列大小减 1。 return process; } // 检查队列是否为空 int isQueueEmpty(PCBQueue* queue) //检查队列是否为空,如果为空则返回 1,否则返回 0。 { return queue->size == 0; } // 显示时间 void displayTime(Time t) { printf("%02d:%02d:%02d", t.hour, t.minute, t.second); } // 显示欢迎界面 void showWelcomeScreen() { system("cls"); printf("============================================\n"); printf("| FCFS算法&RR算法 |\n"); printf("| 第9组 |\n"); printf("| 成员1:202396104025 孙晴 |\n"); printf("| 成员2:202396104026 田舟柯 |\n"); printf("| 成员3:202396104027 拓皓 |\n"); printf("============================================\n\n"); } // 显示菜单 int showMenu() { int choice; printf("\n请选择操作:\n"); printf("1. 输入进程信息\n"); printf("2. 执行FCFS调度算法\n"); printf("3. 执行轮转(RR)调度算法\n"); printf("4. 退出\n"); printf("请输入选项:"); scanf("%d", &choice); return choice; } // 输入进程信息 PCBQueue* inputProcesses() //让用户输入进程信息,创建一个进程队列并返回。 { int n; printf("请输入进程数量(不少于4个):"); scanf("%d", &n); if (n < 4) { printf("进程数量不能少于4个!\n"); return NULL; } PCBQueue* queue = initQueue(n);//初始化一个大小为 n 的进程队列。 printf("请输入%d个进程的信息(进程名称、到达时间(时:分:秒)、运行时间(秒)):\n", n); for (int i = 0; i < n; i++)// 循环读取每个进程的信息。 { PCB process; printf("进程 %d:\n", i + 1); printf("名称: "); scanf("%s", process.name); printf("到达时间(时:分:秒): "); scanf("%d:%d:%d", &process.arrivalTime.hour, &process.arrivalTime.minute, &process.arrivalTime.second); printf("运行时间(秒): "); scanf("%d", &process.burstTime); process.remainingTime = process.burstTime; // 将剩余时间初始化为执行时间 process.startTime = 0; process.completionTime = 0; process.turnaroundTime = 0; process.weightedTurnaroundTime = 0.0; process.waitingTime = 0; process.hasStarted = 0; // 标记进程尚未开始执行 enqueue(queue, process);//将进程插入到队列中。 } return queue; } // 模拟FCFS调度算法 void fcfsScheduling(PCBQueue* processes) { if (processes == NULL || processes->size == 0)//检查是否有进程可供调度 { printf("没有进程可调度!\n"); return; } // 创建一个新的就绪队列 PCBQueue* readyQueue = initQueue(processes->size); // 循环变量,遍历原始进程队列 for (int i = 0; i < processes->size; i++) { enqueue(readyQueue, processes->processes[i]); } printf("\n=========================================\n"); printf(" FCFS调度结果 \n"); printf("=========================================\n"); int currentTime = 0;//模拟CPU时钟 float totalTurnaroundTime = 0;//进程的周转总和 float totalWeightedTurnaroundTime = 0;//带权周转时间总和 printf("\n调度顺序:\n"); printf("进程\t到达时间\t开始时间\t完成时间\t周转时间\t带权周转时间\n"); // 按FCFS顺序处理进程 while (!isQueueEmpty(readyQueue)) { PCB process = dequeue(readyQueue);//现出队操作,并返回队首进程的 PCB。 // 计算开始时间(取当前时间和到达时间的最大值) if (currentTime < timeToSeconds(process.arrivalTime)) { currentTime = timeToSeconds(process.arrivalTime); } process.startTime = currentTime; process.hasStarted = 1; // 标记进程已开始 // 计算完成时间 process.completionTime = currentTime + process.burstTime;//完成时间 = 开始时间 + 执行时间。 // 计算周转时间 process.turnaroundTime = process.completionTime - timeToSeconds(process.arrivalTime);//周转时间 = 完成时间 - 到达时间。 // 计算带权周转时间 process.weightedTurnaroundTime = (float)process.turnaroundTime / process.burstTime;//带权周转时间 = 周转时间 / 执行时间。 // 计算等待时间 process.waitingTime = process.startTime - timeToSeconds(process.arrivalTime);//等待时间 = 开始时间 - 到达时间。 // 更新当前时间 currentTime = process.completionTime; // 输出进程调度信息 printf("%s\t", process.name); displayTime(process.arrivalTime); printf("\t"); displayTime(secondsToTime(process.startTime)); printf("\t"); displayTime(secondsToTime(process.completionTime)); printf("\t%d\t\t%.2f\n", process.turnaroundTime, process.weightedTurnaroundTime); // 累加统计值 totalTurnaroundTime += process.turnaroundTime; totalWeightedTurnaroundTime += process.weightedTurnaroundTime; } // 计算并输出平均值 float avgTurnaroundTime = totalTurnaroundTime / processes->size; float avgWeightedTurnaroundTime = totalWeightedTurnaroundTime / processes->size; printf("\n统计信息:\n"); printf("平均周转时间:%.2f秒\n", avgTurnaroundTime); printf("平均带权周转时间:%.2f\n", avgWeightedTurnaroundTime); // 释放内存 free(readyQueue->processes); free(readyQueue); } // 模拟轮转(RR)调度算法 void rrScheduling(PCBQueue* processes, int quantum)//quantem时间片参数 { if (processes == NULL || processes->size == 0) { printf("没有进程可调度!\n"); return; } // 创建就绪队列和完成队列 PCBQueue* readyQueue = initQueue(processes->size); PCB* completedProcesses = (PCB*)malloc(processes->size * sizeof(PCB)); int completedCount = 0; // 复制原始进程信息到工作队列 PCBQueue* originalQueue = initQueue(processes->size); for (int i = 0; i < processes->size; i++) { enqueue(originalQueue, processes->processes[i]); }//保留原始进程信息,避免修改用户输入数据。 printf("\n=========================================================\n"); printf(" 轮转(RR)调度结果 (时间片=%d秒) \n", quantum); printf("===========================================================\n"); // 找到进程的最早到达时间 int earliestArrival = __INT_MAX__; for (int i = 0; i < originalQueue->size; i++) { int arrivalSec = timeToSeconds(originalQueue->processes[i].arrivalTime); if (arrivalSec < earliestArrival) { earliestArrival = arrivalSec; } } int currentTime = earliestArrival; // 使用最早到达时间初始化 currentTime float totalTurnaroundTime = 0; float totalWeightedTurnaroundTime = 0; printf("\n调度顺序:\n"); printf("进程\t到达时间\t开始时间\t完成时间\t周转时间\t带权周转时间\n"); // RR调度核心逻辑 while (completedCount < processes->size) { // 检查新到达的进程并加入就绪队列(入队) for (int i = 0; i < originalQueue->size; i++) { PCB originalProc = originalQueue->processes[i]; // 只处理未完成且未加入就绪队列的进程 if (timeToSeconds(originalProc.arrivalTime) <= currentTime && originalProc.remainingTime > 0) { // 检查是否已在就绪队列中(避免重复添加) int alreadyInQueue = 0; for (int j = 0; j < readyQueue->size; j++) { if (strcmp(readyQueue->processes[j].name, originalProc.name) == 0) { alreadyInQueue = 1; break; } } if (!alreadyInQueue) { enqueue(readyQueue, originalProc);//调用入队函数 } } } if (isQueueEmpty(readyQueue)) { // 没有可执行进程,时间推进到下一个进程到达时间 int nextArrivalTime = __INT_MAX__; for (int i = 0; i < originalQueue->size; i++) { PCB originalProc = originalQueue->processes[i]; if (originalProc.remainingTime > 0) { int arrivalSec = timeToSeconds(originalProc.arrivalTime); if (arrivalSec < nextArrivalTime) { nextArrivalTime = arrivalSec; } } } // 确保时间不会回退 if (nextArrivalTime > currentTime) { currentTime = nextArrivalTime; } continue; } // 取出一个进程执行 PCB process = dequeue(readyQueue);//调用出队函数 // 记录进程首次开始时间 if (process.hasStarted == 0) { process.startTime = currentTime; process.hasStarted = 1; } // 时间片限制,时间片为quantum int executionTime = (process.remainingTime < quantum)? process.remainingTime : quantum; currentTime += executionTime; process.remainingTime -= executionTime; // 更新原始队列中对应进程的剩余时间 for (int i = 0; i < originalQueue->size; i++) { if (strcmp(originalQueue->processes[i].name, process.name) == 0) { originalQueue->processes[i].remainingTime = process.remainingTime; break; } } // 检查进程是否完成 if (process.remainingTime <= 0) { process.completionTime = currentTime; process.turnaroundTime = process.completionTime - timeToSeconds(process.arrivalTime); process.weightedTurnaroundTime = (float)process.turnaroundTime / process.burstTime; process.waitingTime = process.turnaroundTime - process.burstTime; // 输出进程完成信息 printf("%s\t", process.name); displayTime(process.arrivalTime); printf("\t"); displayTime(secondsToTime(process.startTime)); printf("\t"); displayTime(secondsToTime(process.completionTime)); printf("\t%d\t\t%.2f\n", process.turnaroundTime, process.weightedTurnaroundTime); // 保存到完成队列 completedProcesses[completedCount++] = process; totalTurnaroundTime += process.turnaroundTime; totalWeightedTurnaroundTime += process.weightedTurnaroundTime; } else { // 时间片用完,重新入队 enqueue(readyQueue, process); } } // 计算并输出平均值 float avgTurnaroundTime = totalTurnaroundTime / processes->size; float avgWeightedTurnaroundTime = totalWeightedTurnaroundTime / processes->size; printf("\n统计信息:\n"); printf("平均周转时间:%.2f秒\n", avgTurnaroundTime); printf("平均带权周转时间:%.2f\n", avgWeightedTurnaroundTime); // 释放内存 free(readyQueue->processes); free(readyQueue); free(completedProcesses); free(originalQueue->processes); free(originalQueue); } int main() { PCBQueue* processes = NULL; int choice, quantum; int useDefaultQuantum = 1; // 是否使用默认时间片 showWelcomeScreen(); do { choice = showMenu(); switch (choice) { case 1: if (processes != NULL) { free(processes->processes); free(processes); } processes = inputProcesses(); useDefaultQuantum = 1; // 重置时间片标志 break; case 2: fcfsScheduling(processes); break; case 3: if (processes == NULL || processes->size == 0) { printf("没有进程可调度!请先输入进程信息或加载测试用例\n"); break; } // 询问时间片大小 printf("请输入时间片大小(秒) [默认5秒]: "); if (scanf("%d", &quantum) != 1) { quantum = 5; // 默认时间片 getchar(); // 清除输入缓冲区 printf("使用默认时间片: 5秒\n"); } rrScheduling(processes, quantum); break; case 4: printf("退出程序!\n"); break; default: printf("无效选项,请重新输入!\n"); } } while (choice != 4); // 释放内存 if (processes != NULL) { free(processes->processes); free(processes); } return 0; }这个是我用c语言实现的先来先服务调度算法和轮转调度算法,但是输出给我的先来先服务调度算法和轮转调度算法的结果一样,我的需求是帮我修改轮转调度算法,使其能正确使用时间片,并且修改后的代码只能使用队列,不要让先来先服务调度算法和轮转调度算法相互混淆,修改完成后给我修改后的全部代码
最新发布
06-28
<think>我们注意到在RR调度算法中,存在几个问题:1.在RR算法中,我们使用了一个originalQueue来保存原始进程信息,并且在就绪队列中我们每次从originalQueue中检查到达的进程。但是,在就绪队列中我们加入的是原始队列的副本,而修改剩余时间时修改的是originalQueue中的进程。这样,当我们再次从originalQueue中取进程加入就绪队列时,进程的剩余时间已经被修改了,这是正确的。但是,我们在就绪队列中出队后,对进程的修改(如剩余时间)并没有同步回originalQueue(除了在每次执行后更新剩余时间)。然而,我们在执行过程中,从就绪队列出队的进程是originalQueue中进程的一个副本,所以修改了进程的remainingTime后,我们通过循环更新了originalQueue中对应进程的剩余时间。这一点是做的。2.但是,在RR算法中,我们使用了一个readyQueue,这个队列中的进程是从originalQueue中复制过来的。然而,在调度过程中,我们可能多次将同一个进程加入就绪队列(因为时间片用完但未完成)。但是,我们在加入就绪队列之前会检查是否已经在队列中,避免重复添加。然而,这个检查可能不够高效,而且当进程再次到达时(比如在下一轮)我们还是会加入。3.一个主要的问题是:在RR算法中,我们使用了一个独立的originalQueue来保存进程状态,而就绪队列readyQueue只用于存放当前可以运行的进程(每次从originalQueue中取到达的进程加入)。但是,在调度循环中,我们每次都会扫描整个originalQueue来检查是否有新进程到达,这可能会导致重复添加(尽管我们检查了是否在就绪队列中)。但是,由于我们每次扫描时,进程的剩余时间可能已经改变(因为执行过),所以我们需要避免将已经完成或已经在就绪队列中的进程再次加入。4.另一个问题是:在RR算法中,我们使用了一个数组completedProcesses来保存完成的进程,用于最后统计。但是,在输出时,我们按照进程完成的顺序输出,这是符合RR的。5.然而,我们观察到FCFS和RR的输出结果一样,这说明RR算法并没有按照时间片轮转的方式执行,而是像FCFS一样一次执行完。原因可能在于:-在RR算法中,我们每次从就绪队列中取出一个进程,执行一个时间片,然后如果进程没有完成,我们就将其重新放回就绪队列的末尾。但是,我们的就绪队列是一个有序队列(按到达时间排序)吗?在初始化就绪队列时,我们确实按到达时间排序了。但是,在RR中,我们重新入队时,应该按照什么顺序?实际上,RR算法中,就绪队列应该是先进先出,而不是按到达时间排序。因此,我们的入队函数enqueue是按到达时间排序的,这并不符合RR的要求。因此,我们需要修改RR算法中的就绪队列,使其按照先进先出的顺序,而不是按到达时间排序。所以,我们需要为RR单独实现一个队列,这个队列是FIFO的,而不是按到达时间排序的。修改方案:1.我们保留原来的队列结构,但是修改enqueue函数在RR中的行为:在RR中,我们不需要按到达时间排序,而是直接添加到队尾。因此,我们可以为RR写一个专用的入队函数(比如enqueueRR),它只是简单地将进程添加到数组末尾。2.或者,我们可以修改队列结构,使其支持两种入队方式。但是为了不混淆FCFS和RR,我们选择在RR算法中不使用原来的enqueue函数(因为原来的enqueue是按到达时间排序的),而是使用一个简单的追加到队尾的方式。具体修改:在RR算法中,我们不再使用原来的enqueue函数,而是自己控制入队的位置。我们可以这样做:-初始化就绪队列时,我们创建一个数组,并维护队头和队尾指针(或者使用循环队列)。但是为了简单,我们可以使用一个数组和两个索引(队头front和队尾rear)来实现FIFO队列。但是,为了最小化改动,我们可以修改队列结构,增加一个标志,表示是FCFS队列还是RR队列。但是这样会使得代码复杂。另一种方法是:我们为RR算法单独写一个队列操作函数(在RR函数内部实现一个简单的FIFO队列)。因为RR算法中,队列的操作是:enqueue:添加到队尾dequeue:从队头取出因此,我们可以在RR算法中,不使用原来的PCBQueue,而是自己用数组和两个索引(front和rear)来实现一个循环队列。考虑到时间,我们选择在RR算法中自己实现一个简单的FIFO队列。这样,我们就不会和FCFS的队列混淆。具体步骤:1.在rrScheduling函数中,我们创建一个数组作为就绪队列,并设置队头front和队尾rear,初始都为0。2.队列大小设为进程数量(可能会多次入队,但最多不会超过进程数,因为同一进程不会同时多次在队列中)。3.入队操作:将进程放入rear位置,rear后移(如果rear到达数组末尾,可以循环,但这里简单用rear++,因为进程数固定,不会超过数组大小)。4.出队操作:从front位置取出进程,front后移。注意:数组大小设为进程数*2可能更安全,但理论上,同一时刻就绪队列中的进程数不会超过总进程数。修改rrScheduling函数:-移除原来的readyQueue(即PCBQueue类型),改为用数组和front,rear实现队列。-同时,我们仍然需要originalQueue来保存每个进程的原始信息(主要是剩余时间)吗?是的,因为我们需要更新剩余时间。但是,我们也可以不用originalQueue,而是直接操作一个进程数组。我们将原始进程信息复制到一个数组,然后使用一个独立的就绪队列(存储进程在数组中的索引,或者存储进程的指针)。但为了简单,我们直接存储进程的副本,并更新剩余时间。然而,由于在RR中,同一个进程可能多次进出队列,所以我们需要一个地方保存所有进程的最新状态。我们可以这样做:用一个进程数组(procs)保存所有进程的当前状态(包括剩余时间等)。就绪队列中存储的是进程在数组中的索引。这样,当我们需要执行一个进程时,我们从就绪队列中取出一个索引,然后通过索引修改procs数组中的进程状态。步骤:1.复制原始进程到procs数组。2.初始化就绪队列:一个整数数组(存储索引),以及front和rear。3.将当前时间到达的进程加入就绪队列(加入索引)。4.然后开始循环调度。但是,为了减少改动,我们采用另一种方式:我们仍然保留一个进程数组(即原来的processes->processes的副本),然后我们就绪队列中存储的是指向这个数组中进程的指针?或者存储索引。考虑到C语言中操作索引比较方便,我们存储索引。具体修改如下:由于时间关系,我们决定重写rrScheduling函数中的队列部分。由于代码较长,我们只给出修改后的rrScheduling函数,并注释掉原来的队列操作,改用数组和front, rear实现FIFO队列。注意:我们仍然需要记录每个进程的当前状态(剩余时间、是否开始等)。因此,我们首先创建一个进程数组,复制原始进程,然后我们就绪队列中存储的是这个数组的下标。修改后的rrScheduling函数步骤如下:1.复制原始进程到一个动态数组(procs),数组大小为processes->size。2.创建一个就绪队列(整数数组,存储进程在procs数组中的索引),大小为processes->size *2(保险起见)。3.初始化队列:front=0,rear=0,队列大小=0。4.将当前时间(初始化为最早到达时间)到达的进程加入队列(加入索引)。5.开始循环,直到所有进程完成。6.如果队列不为空,从队头取出一个进程索引,执行一个时间片。7.执行后更新进程的剩余时间,如果剩余时间为0,则标记完成,并计算各项时间。8.否则,将该进程重新加入队尾(注意:重新加入队尾前,需要检查是否有新进程到达,并加入队列)。9.每次时间推进后,检查新到达的进程,并加入队尾(注意避免重复加入已经完成或已经在队列中的进程)。为了避免重复加入,我们可以为每个进程设置一个状态:是否在就绪队列中。但是,为了简单,我们可以在加入队列时检查:如果进程已经完成(剩余时间为0)或者已经在队列中,则跳过。但是,检查是否在队列中需要遍历队列,效率较低。另一种方法:我们可以在进程结构体中增加一个标记(inReadyQueue),表示是否在就绪队列中。但是,由于我们不想修改PCB结构体(因为FCFS不需要),所以我们选择在RR函数内部用一个数组来标记进程是否在就绪队列中。因此,我们创建一个动态数组inQueue,大小为进程数,初始为0。当一个进程加入队列时,标记为1;出队时标记为0。注意:当进程完成时,我们不再加入队列,所以不需要标记。具体步骤:1.初始化:int n= processes->size;PCB*procs= (PCB*)malloc(n* sizeof(PCB));//复制原始进程for(inti=0;i<n; i++) {procs[i] =processes->processes[i];//初始化剩余时间等procs[i].remainingTime =procs[i].burstTime;procs[i].hasStarted=0;}int*readyQueue =(int*)malloc(n *2* sizeof(int));//就绪队列,存储索引int front=0,rear =0;//队列头尾int*inQueue =(int*)calloc(n, sizeof(int));//标记进程是否在就绪队列中,0表示不在2.初始化当前时间:找到最早到达时间3.将当前时间到达的进程加入队列(注意:到达时间<=当前时间,且剩余时间>0,且不在队列中)for(inti=0;i<n; i++) {if(timeToSeconds(procs[i].arrivalTime) <=currentTime&&procs[i].remainingTime >0&&!inQueue[i]){readyQueue[rear++] =i;//加入队尾inQueue[i] =1;//标记为在队列中}}4.循环直到完成所有进程(completedCount <n):while (completedCount< n) {if(front<rear){//队列不为空intidx =readyQueue[front++];//出队inQueue[idx]=0;//标记为不在队列中PCB *proc =&procs[idx];//取进程//如果是第一次运行,设置开始时间if (!proc->hasStarted) {proc->startTime =currentTime;proc->hasStarted=1;}//执行一个时间片int execTime =(proc->remainingTime <quantum)? proc->remainingTime :quantum;currentTime +=execTime;proc->remainingTime-= execTime;//在时间片执行完后,检查新到达的进程for (int i=0; i<n;i++){if (!inQueue[i]&& procs[i].remainingTime>0 &&timeToSeconds(procs[i].arrivalTime)<= currentTime){//加入就绪队列readyQueue[rear++]= i;inQueue[i]=1;}}//检查当前进程是否完成if (proc->remainingTime<=0){//完成,计算各项时间proc->completionTime= currentTime;proc->turnaroundTime= currentTime -timeToSeconds(proc->arrivalTime);proc->weightedTurnaroundTime= (float)proc->turnaroundTime /proc->burstTime;proc->waitingTime =proc->turnaroundTime -proc->burstTime;//输出printf("%s\t",proc->name);displayTime(proc->arrivalTime);printf("\t");displayTime(secondsToTime(proc->startTime)); printf("\t");displayTime(secondsToTime(proc->completionTime)); printf("\t");printf("%d\t\t%.2f\n", proc->turnaroundTime, proc->weightedTurnaroundTime);completedCount++;totalTurnaroundTime+= proc->turnaroundTime;totalWeightedTurnaroundTime+= proc->weightedTurnaroundTime;} else{//未完成,重新加入队尾readyQueue[rear++]= idx;inQueue[idx]=1;}}else {//队列为空,则推进时间到下一个到达的进程int nextTime =__INT_MAX__;for (int i=0; i<n;i++){if (procs[i].remainingTime>0) {intat= timeToSeconds(procs[i].arrivalTime);if (at <nextTime&&at >currentTime) {nextTime =at;}}}if(nextTime ==__INT_MAX__)break; //没有进程了,应该不会发生currentTime =nextTime;//将此时到达的进程加入队列for(inti=0;i<n; i++) {if(!inQueue[i] &&procs[i].remainingTime>0&&timeToSeconds(procs[i].arrivalTime) <=currentTime) {readyQueue[rear++]= i;inQueue[i]=1;}}}}5.释放内存:free(procs);free(readyQueue); free(inQueue);注意:在加入新进程时,我们只加入不在队列中且到达时间<=当前时间的进程。由于时间关系,我们按照上述思路重写rrScheduling函数。但是,由于整个代码较长,我们只给出修改后的rrScheduling函数,并在注释中解释。注意:我们不再使用原来的PCBQueue结构,因此可以删除原来在rrScheduling中关于PCBQueue的操作。修改后的全部代码:</think>您的代码中存在一个关键问题:在轮转调度算法中,使用了一个按到达时间排序的队列,这与轮转调度要求的先进先出(FIFO)队列行为不符。此外,RR算法中的进程管理逻辑也需要调整。以下是修改后的完整代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <limits.h> // 定义时间结构体,精确到秒 typedef struct { int hour; int minute; int second; } Time; // 进程控制块PCB typedef struct PCB { char name[20]; // 进程名称 Time arrivalTime; // 到达时间 int burstTime; // 运行时间(秒) int remainingTime; // 剩余运行时间(秒),用于RR算法 int startTime; // 开始时间(秒) int completionTime; // 完成时间(秒) int turnaroundTime; // 周转时间 float weightedTurnaroundTime; // 带权周转时间 int waitingTime; // 等待时间 int hasStarted; // 标记进程是否已开始执行 } PCB; // PCB队列 typedef struct { PCB* processes; // 进程数组 int capacity; // 队列容量 int size; // 当前队列大小 } PCBQueue; // 初始化就绪队列 PCBQueue* initQueue(int capacity) { PCBQueue* queue = (PCBQueue*)malloc(sizeof(PCBQueue)); queue->processes = (PCB*)malloc(capacity * sizeof(PCB)); queue->capacity = capacity; queue->size = 0; return queue; } // 将时间转换为总秒数 int timeToSeconds(Time t) { return t.hour * 3600 + t.minute * 60 + t.second; } // 将总秒数转换为时间格式 Time secondsToTime(int seconds) { Time t; t.hour = seconds / 3600; t.minute = (seconds % 3600) / 60; t.second = seconds % 60; return t; } // 入队函数: void enqueue(PCBQueue* queue, PCB process) { if (queue->size >= queue->capacity) { printf("队列已满,无法插入进程\n"); return; } // 找到插入位置,保持到达时间有序 int i; for (i = queue->size; i > 0; i--) { if (timeToSeconds(process.arrivalTime) >= timeToSeconds(queue->processes[i - 1].arrivalTime)) { break;//找到插入位置,将到达时间晚的进程后移。 } queue->processes[i] = queue->processes[i - 1];//将进程插入到合适的位置。 } queue->processes[i] = process; queue->size++; } // 出队函数 PCB dequeue(PCBQueue* queue) //从队列中取出一个进程,按到达时间顺序。 { if (queue->size == 0) { printf("队列为空,无法取出进程\n"); exit(1); } PCB process = queue->processes[0]; // 取出队列的第一个进程。 for (int i = 0; i < queue->size - 1; i++)//将后面的进程前移。 { queue->processes[i] = queue->processes[i + 1]; } queue->size--;//队列大小减 1。 return process; } // 检查队列是否为空 int isQueueEmpty(PCBQueue* queue) //检查队列是否为空,如果为空则返回 1,否则返回 0。 { return queue->size == 0; } // 显示时间 void displayTime(Time t) { printf("%02d:%02d:%02d", t.hour, t.minute, t.second); } // 显示欢迎界面 void showWelcomeScreen() { system("cls"); printf("============================================\n"); printf("| FCFS算法&RR算法 |\n"); printf("| 第9组 |\n"); printf("| 成员1:202396104025 孙晴 |\n"); printf("| 成员2:202396104026 田舟柯 |\n"); printf("| 成员3:202396104027 拓皓 |\n"); printf("============================================\n\n"); } // 显示菜单 int showMenu() { int choice; printf("\n请选择操作:\n"); printf("1. 输入进程信息\n"); printf("2. 执行FCFS调度算法\n"); printf("3. 执行轮转(RR)调度算法\n"); printf("4. 退出\n"); printf("请输入选项:"); scanf("%d", &choice); return choice; } // 输入进程信息 PCBQueue* inputProcesses() //让用户输入进程信息,创建一个进程队列并返回。 { int n; printf("请输入进程数量(不少于4个):"); scanf("%d", &n); if (n < 4) { printf("进程数量不能少于4个!\n"); return NULL; } PCBQueue* queue = initQueue(n);//初始化一个大小为 n 的进程队列。 printf("请输入%d个进程的信息(进程名称、到达时间(时:分:秒)、运行时间(秒)):\n", n); for (int i = 0; i < n; i++)// 循环读取每个进程的信息。 { PCB process; printf("进程 %d:\n", i + 1); printf("名称: "); scanf("%s", process.name); printf("到达时间(时:分:秒): "); scanf("%d:%d:%d", &process.arrivalTime.hour, &process.arrivalTime.minute, &process.arrivalTime.second); printf("运行时间(秒): "); scanf("%d", &process.burstTime); process.remainingTime = process.burstTime; // 将剩余时间初始化为执行时间 process.startTime = 0; process.completionTime = 0; process.turnaroundTime = 0; process.weightedTurnaroundTime = 0.0; process.waitingTime = 0; process.hasStarted = 0; // 标记进程尚未开始执行 enqueue(queue, process);//将进程插入到队列中。 } return queue; } // 模拟FCFS调度算法 void fcfsScheduling(PCBQueue* processes) { if (processes == NULL || processes->size == 0)//检查是否有进程可供调度 { printf("没有进程可调度!\n"); return; } // 创建一个新的就绪队列 PCBQueue* readyQueue = initQueue(processes->size); // 循环变量,遍历原始进程队列 for (int i = 0; i < processes->size; i++) { enqueue(readyQueue, processes->processes[i]); } printf("\n=========================================\n"); printf(" FCFS调度结果 \n"); printf("=========================================\n"); int currentTime = 0;//模拟CPU时钟 float totalTurnaroundTime = 0;//进程的周转总和 float totalWeightedTurnaroundTime = 0;//带权周转时间总和 printf("\n调度顺序:\n"); printf("进程\t到达时间\t开始时间\t完成时间\t周转时间\t带权周转时间\n"); // 按FCFS顺序处理进程 while (!isQueueEmpty(readyQueue)) { PCB process = dequeue(readyQueue);//现出队操作,并返回队首进程的 PCB。 // 计算开始时间(取当前时间和到达时间的最大值) if (currentTime < timeToSeconds(process.arrivalTime)) { currentTime = timeToSeconds(process.arrivalTime); } process.startTime = currentTime; process.hasStarted = 1; // 标记进程已开始 // 计算完成时间 process.completionTime = currentTime + process.burstTime;//完成时间 = 开始时间 + 执行时间。 // 计算周转时间 process.turnaroundTime = process.completionTime - timeToSeconds(process.arrivalTime);//周转时间 = 完成时间 - 到达时间。 // 计算带权周转时间 process.weightedTurnaroundTime = (float)process.turnaroundTime / process.burstTime;//带权周转时间 = 周转时间 / 执行时间。 // 计算等待时间 process.waitingTime = process.startTime - timeToSeconds(process.arrivalTime);//等待时间 = 开始时间 - 到达时间。 // 更新当前时间 currentTime = process.completionTime; // 输出进程调度信息 printf("%s\t", process.name); displayTime(process.arrivalTime); printf("\t"); displayTime(secondsToTime(process.startTime)); printf("\t"); displayTime(secondsToTime(process.completionTime)); printf("\t%d\t\t%.2f\n", process.turnaroundTime, process.weightedTurnaroundTime); // 累加统计值 totalTurnaroundTime += process.turnaroundTime; totalWeightedTurnaroundTime += process.weightedTurnaroundTime; } // 计算并输出平均值 float avgTurnaroundTime = totalTurnaroundTime / processes->size; float avgWeightedTurnaroundTime = totalWeightedTurnaroundTime / processes->size; printf("\n统计信息:\n"); printf("平均周转时间:%.2f秒\n", avgTurnaroundTime); printf("平均带权周转时间:%.2f\n", avgWeightedTurnaroundTime); // 释放内存 free(readyQueue->processes); free(readyQueue); } // 模拟轮转(RR)调度算法 void rrScheduling(PCBQueue* processes, int quantum) { if (processes == NULL || processes->size == 0) { printf("没有进程可调度!\n"); return; } // 创建进程副本数组 int n = processes->size; PCB* procs = (PCB*)malloc(n * sizeof(PCB)); for (int i = 0; i < n; i++) { procs[i] = processes->processes[i]; procs[i].remainingTime = procs[i].burstTime; // 重置剩余时间 procs[i].hasStarted = 0; // 重置开始标记 } // 创建RR专用队列(FIFO顺序) int* readyQueue = (int*)malloc(n * 2 * sizeof(int)); // 存储进程索引 int front = 0, rear = 0; // 队列头尾指针 int* inQueue = (int*)calloc(n, sizeof(int)); // 标记进程是否在队列中 printf("\n=========================================================\n"); printf(" 轮转(RR)调度结果 (时间片=%d秒) \n", quantum); printf("===========================================================\n"); // 初始化当前时间 int currentTime = INT_MAX; for (int i = 0; i < n; i++) { int arrivalSec = timeToSeconds(procs[i].arrivalTime); if (arrivalSec < currentTime) { currentTime = arrivalSec; } } float totalTurnaroundTime = 0; float totalWeightedTurnaroundTime = 0; int completedCount = 0; printf("\n调度顺序:\n"); printf("进程\t到达时间\t开始时间\t完成时间\t周转时间\t带权周转时间\n"); // 初始加入所有到达的进程 for (int i = 0; i < n; i++) { if (timeToSeconds(procs[i].arrivalTime) <= currentTime) { readyQueue[rear++] = i; // 加入队尾 inQueue[i] = 1; // 标记在队列中 } } // RR调度核心逻辑 while (completedCount < n) { if (front == rear) { // 队列为空 // 找到下一个到达的进程 int nextArrival = INT_MAX; for (int i = 0; i < n; i++) { if (procs[i].remainingTime > 0) { int arrivalSec = timeToSeconds(procs[i].arrivalTime); if (arrivalSec < nextArrival && arrivalSec > currentTime) { nextArrival = arrivalSec; } } } if (nextArrival == INT_MAX) break; // 所有进程已完成 currentTime = nextArrival; // 加入新到达的进程 for (int i = 0; i < n; i++) { if (!inQueue[i] && procs[i].remainingTime > 0 && timeToSeconds(procs[i].arrivalTime) <= currentTime) { readyQueue[rear++] = i; inQueue[i] = 1; } } continue; } // 取出队首进程 int idx = readyQueue[front++]; inQueue[idx] = 0; // 标记不在队列中 PCB* proc = &procs[idx]; // 记录首次开始时间 if (!proc->hasStarted) { proc->startTime = currentTime; proc->hasStarted = 1; } // 执行时间片 int execTime = (proc->remainingTime < quantum) ? proc->remainingTime : quantum; currentTime += execTime; proc->remainingTime -= execTime; // 加入新到达的进程 for (int i = 0; i < n; i++) { if (!inQueue[i] && procs[i].remainingTime > 0 && timeToSeconds(procs[i].arrivalTime) <= currentTime) { readyQueue[rear++] = i; inQueue[i] = 1; } } // 检查进程是否完成 if (proc->remainingTime <= 0) { proc->completionTime = currentTime; proc->turnaroundTime = currentTime - timeToSeconds(proc->arrivalTime); proc->weightedTurnaroundTime = (float)proc->turnaroundTime / proc->burstTime; proc->waitingTime = proc->turnaroundTime - proc->burstTime; // 输出进程完成信息 printf("%s\t", proc->name); displayTime(proc->arrivalTime); printf("\t"); displayTime(secondsToTime(proc->startTime)); printf("\t"); displayTime(secondsToTime(proc->completionTime)); printf("\t%d\t\t%.2f\n", proc->turnaroundTime, proc->weightedTurnaroundTime); completedCount++; totalTurnaroundTime += proc->turnaroundTime; totalWeightedTurnaroundTime += proc->weightedTurnaroundTime; } else { // 未完成,重新加入队尾 readyQueue[rear++] = idx; inQueue[idx] = 1; } } // 计算并输出平均值 float avgTurnaroundTime = totalTurnaroundTime / n; float avgWeightedTurnaroundTime = totalWeightedTurnaroundTime / n; printf("\n统计信息:\n"); printf("平均周转时间:%.2f秒\n", avgTurnaroundTime); printf("平均带权周转时间:%.2f\n", avgWeightedTurnaroundTime); // 释放内存 free(procs); free(readyQueue); free(inQueue); } int main() { PCBQueue* processes = NULL; int choice, quantum; showWelcomeScreen(); do { choice = showMenu(); switch (choice) { case 1: if (processes != NULL) { free(processes->processes); free(processes); } processes = inputProcesses(); break; case 2: fcfsScheduling(processes); break; case 3: if (processes == NULL || processes->size == 0) { printf("没有进程可调度!请先输入进程信息\n"); break; } // 询问时间片大小 printf("请输入时间片大小(秒) [默认5秒]: "); if (scanf("%d", &quantum) != 1) { quantum = 5; // 默认时间片 getchar(); // 清除输入缓冲区 printf("使用默认时间片: 5秒\n"); } rrScheduling(processes, quantum); break; case 4: printf("退出程序!\n"); break; default: printf("无效选项,请重新输入!\n"); } } while (choice != 4); // 释放内存 if (processes != NULL) { free(processes->processes); free(processes); } return 0; } ``` ### 主要修改说明: 1. **RR算法完全重构**: - 创建了独立的进程副本数组 `procs`,避免修改原始数据 - 使用整数数组 `readyQueue` 存储进程索引实现真正的FIFO队列 - 添加 `inQueue` 数组跟踪进程是否已在队列中 2. **队列管理优化**: - 移除了原有的PCBQueue结构在RR中的使用 - 使用 `front` 和 `rear` 指针管理队列 - 进程执行后未完成时重新加入队尾 3. **时间片处理逻辑**: ```c int execTime = (proc->remainingTime < quantum) ? proc->remainingTime : quantum; currentTime += execTime; proc->remainingTime -= execTime; ``` 这段代码确保正确处理时间片和剩余时间的关系 4. **新进程加入机制**: ```c for (int i = 0; i < n; i++) { if (!inQueue[i] && procs[i].remainingTime > 0 && timeToSeconds(procs[i].arrivalTime) <= currentTime) { readyQueue[rear++] = i; inQueue[i] = 1; } } ``` 每次时间推进后检查并加入新到达的进程 5. **空闲时间处理**: ```c if (front == rear) { // 队列为空 // 找到下一个到达的进程 int nextArrival = INT_MAX; for (int i = 0; i < n; i++) { if (procs[i].remainingTime > 0) { int arrivalSec = timeToSeconds(procs[i].arrivalTime); if (arrivalSec < nextArrival && arrivalSec > currentTime) { nextArrival = arrivalSec; } } } // ... 更新当前时间并加入新进程 } ``` 当就绪队列为空时,直接跳到下一个进程到达时间 ### 测试建议: 1. 输入4个进程进行测试 2. 尝试不同时间片大小(如2秒、5秒) 3. 观察RR调度结果与FCFS的区别 4. 特别注意带权周转时间的变化
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值