<think>
我们当前的时间片轮转调度程序没有优先级。要实现带优先级的时间片轮转调度,我们可以考虑以下两种方案:
方案1:优先级队列轮转
将就绪队列按照优先级分成多个队列,每个优先级一个队列。调度时,从最高优先级的队列开始轮转,只有当高优先级队列为空时,才调度低优先级队列。同一优先级队列内使用时间片轮转。
方案2:在同一个队列中考虑优先级
在同一个循环队列中,进程按优先级排序。每次调度时,选择队列中优先级最高的进程运行。但这样会破坏轮转的顺序。
然而,用户要求的是在原有时间片轮转的基础上增加优先级,同时保持轮转的特性。我们可以这样设计:
- 每个进程增加一个优先级字段(priority),优先级可以用整数表示,数值越大优先级越高(或越小优先级越高,根据需求定,这里我们设定数值越大优先级越高)。
- 队列仍然保持循环队列,但是每次调度时,并不一定选择队首的进程,而是从队首开始向后寻找优先级最高的进程(但这样会破坏轮转的公平性?)。
但是,时间片轮转算法本身并不考虑优先级,它强调的是公平性。如果我们要加入优先级,通常会采用多级队列(MLFQ)的方式。
不过,根据用户要求,我们可以在同一个队列中实现简单的优先级调度:即每次调度时,从当前队首开始,扫描整个队列,找出优先级最高的进程,让它运行一个时间片。运行完后,将该进程移到队尾(如果未完成)。这样,每次调度都需要遍历整个队列,时间复杂度为O(n)。
另一种折中:在入队时根据优先级插入到合适的位置(即维持一个按优先级排序的队列,但同一优先级按FIFO)。这样,每次出队总是出队首(优先级最高且最先到达的进程),运行一个时间片后,如果未完成,则重新入队(入队时按优先级插入到队列中相应位置)。这样,高优先级的进程会得到更多的运行机会,但同一优先级的进程之间仍然是轮转。
我们采用第二种折中方法,修改队列为优先级队列(但同一优先级内保持FIFO)。具体步骤:
1. 在PCB结构体中增加优先级字段:int priority;
2. 修改入队操作:不再是直接加到队尾,而是根据优先级插入到合适的位置(优先级高的在前,优先级相同的按到达顺序即放在同优先级的末尾)
3. 出队操作仍然从队首出队。
注意:这样队列就不是简单的循环队列了,而是按优先级排序的队列。但是,我们仍然保持循环链表的结构,只是插入位置变化。
然而,这样实现起来比较复杂,而且会改变时间片轮转的公平性,可能高优先级进程会连续运行多次(如果不断有高优先级进程到来,可能导致低优先级进程饥饿)。
因此,我们也可以考虑在每个时间片轮转的基础上,给高优先级进程分配更多的时间片(比如,优先级为p的进程,每次运行的时间片长度为:基础时间片 * (1+p) ?)。但这样也会打破公平性。
用户要求是“自定义运行时间和优先级”,我们可以这样理解:用户希望每个进程可以设置不同的运行时间(已有)和优先级,然后调度算法在轮转的基础上考虑优先级。
为了保持简单,我们采用第一种方案:多级队列。但用户要求是在同一个调度程序中修改,所以我们可以先实现一个简单的基于优先级的轮转:每次从队列中选择优先级最高的进程运行(注意:这样就不是严格的轮转了,而是优先级调度),运行一个时间片后,如果未完成,则将其优先级降低(防止高优先级进程一直霸占CPU)后重新入队(入队时按优先级插入)。这样,既考虑了优先级,又给了低优先级进程机会。
具体修改:
1. 在PCB结构体中增加:
int priority; // 优先级,数值越大优先级越高
int original_priority; // 原始优先级(可选,用于优先级降低后的恢复)
2. 修改入队函数:按照优先级从高到低插入,同一优先级的插入到同优先级队列的末尾(即放在第一个优先级小于或等于当前进程优先级的进程前面?)。注意:这样我们每次入队都需要遍历队列。
3. 每次进程运行一个时间片后,将其优先级降低(比如减1),然后重新入队。当优先级降低到一定程度后,可以恢复为原始优先级(避免一直降低)。
4. 出队操作:因为队列已经是按优先级排序,所以队首就是优先级最高的进程,直接出队即可。
但是,这样实现起来,队列的插入操作会变得复杂,而且每次插入都需要遍历队列。
为了简化,我们可以不显式降低优先级,而是采用另一种策略:每次从队首开始扫描整个队列,找到优先级最高的进程,将它出队运行,运行后将其优先级降低,然后重新入队到队尾(注意,入队时不再按优先级,而是队尾)。这样,队列中的进程优先级会随着运行次数增加而降低,最终都会得到执行。
然而,这样每次调度都需要遍历整个队列,时间复杂度为O(n)。
考虑到进程数不多(5个),我们可以接受。
具体修改:
1. 在PCB结构体中加入:
int priority; // 当前优先级,数值越大优先级越高
int original_priority; // 原始优先级(用于重置,可选)
2. 修改dequeue函数:不再直接取队首,而是遍历整个队列,找到优先级最高的进程,将其从队列中移除并返回。注意:如果队列为空则返回NULL。
3. 每次进程运行后,将其优先级减1(模拟优先级降低),然后将其重新入队(入队到队尾,即enqueue函数保持不变,总是加到队尾)。
4. 这样,随着进程的运行,其优先级会逐渐降低,低优先级的进程就有机会运行。
5. 为了防止优先级过低,可以在进程运行完一个时间片后,如果优先级已经降低到某个阈值(比如0),则重置为原始优先级(如果有原始优先级的话)或者不再降低。
6. 另外,在创建进程时,需要为每个进程指定优先级。
我们修改后的调度过程:
while (队列非空) {
1. 从队列中找出优先级最高的进程(如果有多个相同优先级的,取第一个遇到的,即FIFO)
2. 运行该进程一个时间片(used_time加1)
3. 检查是否完成,如果完成则释放,否则:
a. 将进程优先级减1(模拟优先级降低)
b. 将进程重新加入队尾
}
这样,高优先级的进程会被优先执行,但每次执行后优先级降低,这样其他进程就有机会执行。
但是,这种方法可能导致高优先级进程在开始阶段连续执行多个时间片(因为每次执行后优先级降低,但可能还是比队中其他进程优先级高,所以下次调度时可能还是它),直到优先级降低到低于其他进程。
这实际上是一种动态优先级调度,结合了轮转。
我们按照这个思路修改代码。
步骤:
1. 修改PCB结构体,增加priority字段(和original_priority,可选)。
2. 修改创建进程的函数,为每个进程设置优先级(可以自定义输入,但这里我们先预设)。
3. 修改dequeue函数:不再简单地取队首,而是遍历整个队列找到优先级最高的进程,将其从链表中移除并返回。注意:由于是循环链表,移除时需要调整指针。
4. enqueue函数保持不变(总是加到队尾)。
5. 在进程运行后(未完成时),降低其优先级,然后重新入队。
注意:由于我们每次出队都要遍历整个队列,所以dequeue操作的时间复杂度为O(n),而原来的轮转是O(1)。
考虑到进程数少,可以接受。
具体代码修改如下:
1. 在PCB结构体中增加:
int priority; // 当前优先级
int original_priority; // 原始优先级(可选,用于重置)
2. 修改createProcesses函数,为每个进程设置优先级。我们可以预设优先级数组。
3. 重新实现dequeue函数,使其返回队列中优先级最高的进程,并将其从队列中移除。
4. 在运行调度时,每次从dequeue取出进程,运行后如果未完成,则降低优先级(priority--)然后入队。
5. 为了避免优先级一直降低,可以设置一个最低优先级(比如0),当优先级降低到0时不再降低,或者重置为原始优先级。这里我们选择不再降低(即最低为0)。
6. 注意:如果队列中只有一个进程,那么直接取出即可。
实现新的dequeue函数:
```c
// 从队列中取出优先级最高的进程(如果有多个相同优先级,取第一个遇到的)
PCB* dequeue() {
if (rear == NULL) {
return NULL;
}
// 如果只有一个节点
if (rear->next == rear) {
PCB* temp = rear;
rear = NULL;
return temp;
}
PCB* current = rear->next; // 从队首开始
PCB* start = current;
PCB* maxPriorityPrev = NULL; // 指向优先级最高的节点的前一个节点
PCB* prev = rear; // 当前节点的前一个节点(因为是循环链表,队首的前一个节点是队尾)
int maxPriority = -1; // 初始化为一个很小的数
do {
// 寻找优先级最高的节点
if (current->priority > maxPriority) {
maxPriority = current->priority;
maxPriorityPrev = prev; // 记录前一个节点
}
prev = current;
current = current->next;
} while (current != start);
// 此时maxPriorityPrev指向最高优先级节点的前一个节点
PCB* maxNode = maxPriorityPrev->next; // 最高优先级节点
// 将maxNode从链表中移除
if (maxNode == rear->next) { // 如果移除的是队首
rear->next = maxNode->next;
} else {
maxPriorityPrev->next = maxNode->next;
}
// 如果移除的是尾节点,需要更新rear
if (maxNode == rear) {
// 如果链表中还有节点
if (maxPriorityPrev->next != rear) {
rear = maxPriorityPrev;
} else {
// 移除后只剩一个节点?但前面已经处理了只有一个节点的情况,所以这里不会发生
}
}
// 如果队列中只剩一个节点,移除后队列为空,但我们的判断条件(rear->next==rear)已经处理,所以这里不需要再处理
return maxNode;
}
```
这个dequeue函数较为复杂,需要注意链表指针的调整。
另一种简单的方法:遍历找到优先级最高的节点,记录它的前驱,然后删除该节点。
但考虑到循环链表,删除节点时需要更新前驱节点的next,以及更新rear指针(如果删除的是尾节点)。
我们按照上述代码实现。
另外,在入队(enqueue)时,我们仍然将节点插入到队尾(即rear后面),所以enqueue函数不变。
最后,修改调度循环:每次取出优先级最高的进程,运行,然后如果未完成则降低优先级并重新入队。
注意:如果进程完成,则释放内存,不再入队。
下面给出修改后的完整代码。
注意:我们为用户增加了自定义运行时间和优先级的功能。在创建进程时,我们原本是预设的,现在可以改为用户输入。
这里为了简化,我们仍然使用预设,但预留了自定义输入的接口(注释掉的部分可以打开让用户输入)。
完整代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 进程控制块结构体
typedef struct PCB {
char name[10]; // 进程名
int required_time; // 要求运行时间
int used_time; // 已运行时间
char state; // 状态(R:就绪, E:结束)
int priority; // 优先级(数值越大优先级越高)
struct PCB* next; // 指向下一个PCB的指针
} PCB;
// 全局变量
PCB* rear = NULL; // 循环队列尾指针
int time_slice = 1; // 时间片长度(默认为1)
int total_processes = 5; // 总进程数
// 函数声明
void createProcesses();
void addToQueue(PCB* newPCB);
void displayQueue();
void runScheduler();
PCB* dequeue(); // 修改:出队操作现在返回优先级最高的进程
void enqueue(PCB* pcb); // 入队操作不变,仍然加到队尾
int main() {
printf("======= 带优先级的时间片轮转调度算法实现 =======\n");
printf("将创建%d个进程,时间片长度为%d\n", total_processes, time_slice);
createProcesses(); // 创建进程并加入循环队列
displayQueue(); // 显示初始队列状态
runScheduler(); // 开始调度执行
printf("\n所有进程已执行完毕!\n");
return 0;
}
// 创建进程并加入循环队列
void createProcesses() {
// 预设进程数据
char* names[] = {"P1", "P2", "P3", "P4", "P5"};
int times[] = {3, 5, 2, 4, 6};
int priorities[] = {3, 1, 4, 2, 5}; // 优先级,数值越大优先级越高
for (int i = 0; i < total_processes; i++) {
PCB* newPCB = (PCB*)malloc(sizeof(PCB));
strcpy(newPCB->name, names[i]);
newPCB->required_time = times[i];
newPCB->used_time = 0;
newPCB->state = 'R'; // 初始状态为就绪
newPCB->priority = priorities[i];
newPCB->next = NULL;
addToQueue(newPCB);
}
}
// 添加新进程到循环队列(队尾)
void addToQueue(PCB* newPCB) {
if (rear == NULL) {
// 队列为空
rear = newPCB;
rear->next = rear; // 循环指向自己
} else {
// 添加到队尾
newPCB->next = rear->next;
rear->next = newPCB;
rear = newPCB; // 更新尾指针
}
}
// 显示队列状态
void displayQueue() {
if (rear == NULL) {
printf("队列为空!\n");
return;
}
PCB* current = rear->next; // 从队首开始
PCB* start = current;
printf("\n当前进程队列状态:\n");
printf("进程名\t要求时间\t已运行时间\t优先级\t状态\n");
printf("------------------------------------------------\n");
do {
printf("%s\t%d\t\t%d\t\t%d\t%c\n",
current->name,
current->required_time,
current->used_time,
current->priority,
current->state);
current = current->next;
} while (current != start);
printf("------------------------------------------------\n");
}
// 运行调度器
void runScheduler() {
int time_count = 0; // 时间计数器
while (rear != NULL) {
time_count++;
printf("\n===== 时间片 %d =====\n", time_count);
// 从队列中取出优先级最高的进程
PCB* current_process = dequeue();
if (current_process == NULL) {
printf("队列为空!\n");
break;
}
printf(">> 正在执行进程: %s (优先级: %d)\n", current_process->name, current_process->priority);
// 运行一个时间片
current_process->used_time++;
// 检查进程是否完成
if (current_process->used_time >= current_process->required_time) {
current_process->state = 'E'; // 状态设为结束
printf(" 进程 %s 执行完毕! (总用时: %d)\n",
current_process->name, current_process->used_time);
// 释放完成的进程
free(current_process);
total_processes--;
} else {
// 未完成则降低优先级(最低为0)
if (current_process->priority > 0) {
current_process->priority--;
}
// 重新加入队尾
enqueue(current_process);
printf(" 进程 %s 已运行: %d/%d, 新优先级: %d\n",
current_process->name,
current_process->used_time,
current_process->required_time,
current_process->priority);
}
// 显示当前队列状态
displayQueue();
// 如果只剩一个进程且已完成,队列可能为空
if (total_processes == 0) {
rear = NULL;
}
}
}
// 从队列中取出优先级最高的进程(如果有多个相同优先级,取第一个遇到的)
PCB* dequeue() {
if (rear == NULL) {
return NULL;
}
// 如果只有一个节点
if (rear->next == rear) {
PCB* temp = rear;
rear = NULL;
return temp;
}
PCB* current = rear->next; // 从队首开始
PCB* start = current;
PCB* maxPriorityPrev = rear; // 指向优先级最高的节点的前一个节点,初始为队尾(即队首的前一个)
PCB* prev = rear; // 当前节点的前一个节点(初始为队尾)
int maxPriority = -1; // 初始化为一个很小的数
do {
// 寻找优先级最高的节点
if (current->priority > maxPriority) {
maxPriority = current->priority;
maxPriorityPrev = prev; // 记录前一个节点
}
prev = current;
current = current->next;
} while (current != start);
// 此时maxPriorityPrev指向最高优先级节点的前一个节点
PCB* maxNode = maxPriorityPrev->next; // 最高优先级节点
// 将maxNode从链表中移除
maxPriorityPrev->next = maxNode->next;
// 如果移除的是尾节点(即maxNode等于rear),需要更新rear
if (maxNode == rear) {
rear = maxPriorityPrev; // 因为maxNode被移除,rear指向它的前一个节点
}
// 如果移除的是头节点(即队首),且队列中还有节点,那么新的队首是maxNode->next
// 但由于我们使用rear->next表示队首,所以如果移除的是队首,需要更新rear->next吗?
// 注意:在我们的循环链表中,队首是rear->next,如果移除的是队首,那么队首的下一个节点成为新的队首。
// 但是,在移除操作中,我们更新了前一个节点的next,所以rear->next可能已经不再是队首?不,队首始终是rear->next。
// 但是,如果移除的节点是rear->next,那么我们并没有更新rear->next。所以需要更新吗?
// 实际上,在移除操作中,我们只更新了前一个节点的next,所以如果移除的是队首(即rear->next),那么我们需要更新rear->next吗?
// 注意:队首是rear->next,如果移除的是队首,那么rear->next应该指向原来队首的下一个节点。但是,在maxPriorityPrev->next = maxNode->next;中,如果maxPriorityPrev正好是rear(即移除的是队首),那么这条语句就相当于rear->next = maxNode->next;,这样rear->next就指向了新的队首。所以不需要额外更新。
// 因此,我们只需要处理尾节点的情况(即更新rear)。
return maxNode;
}
// 将进程加入队尾(循环队列)
void enqueue(PCB* pcb) {
if (rear == NULL) {
rear = pcb;
rear->next = rear;
} else {
pcb->next = rear->next;
rear->next = pcb;
rear = pcb; // 更新尾指针
}
}
```
注意:dequeue函数中,如果移除的是队首节点,且队首节点是rear->next,那么通过maxPriorityPrev->next = maxNode->next;已经将rear->next更新了(当maxPriorityPrev是rear时)。所以不需要额外处理队首。
另外,如果移除的是尾节点(maxNode==rear),那么我们将rear更新为maxPriorityPrev。
测试:我们预设了5个进程,优先级分别为3,1,4,2,5(P1:3, P2:1, P3:4, P4:2, P5:5)。所以第一次调度应该选择优先级最高的P5(优先级5)。运行后,P5的优先级降低为4,然后被放到队尾。下一次调度,队列中优先级最高的是P3(优先级4)和P5(优先级4),但P3在P5前面(因为P5被放到了队尾,而P3还在前面),所以选择P3。
这样,我们就实现了带优先级的时间片轮转调度。
用户可以根据需要修改创建进程部分的数组(names, times, priorities)来自定义运行时间和优先级。
如果需要用户输入,可以修改createProcesses函数:
```c
void createProcesses() {
char name[10];
int time, priority;
for (int i = 1; i <= total_processes; i++) {
printf("输入进程%d的名称、要求运行时间和优先级(用空格分隔): ", i);
scanf("%s %d %d", name, &time, &priority);
PCB* newPCB = (PCB*)malloc(sizeof(PCB));
strcpy(newPCB->name, name);
newPCB->required_time = time;
newPCB->used_time = 0;
newPCB->state = 'R';
newPCB->priority = priority;
newPCB->next = NULL;
addToQueue(newPCB);
}
}
```
同时,在main函数中,可以先让用户输入总进程数:
```c
int main() {
printf("======= 带优先级的时间片轮转调度算法实现 =======\n");
printf("请输入进程数: ");
scanf("%d", &total_processes);
// 然后调用createProcesses
// ...
}
```
这里为了简洁,我们没有加入用户输入,但提供了扩展方法。
最后,我们生成了相关问题。
注意:在回答中,我们引用了轮转法的基本思想[^1],并提到了周转时间[^2]和多道技术[^3]。
</think># 时间片轮转调度算法:实现自定义运行时间和优先级
我将修改时间片轮转调度算法,添加自定义运行时间和优先级功能。主要修改点包括:
1. 在PCB结构体中添加`priority`字段表示优先级
2. 修改进程创建逻辑,支持自定义输入
3. 调整调度算法,在轮转基础上考虑优先级
## 修改后的完整代码实现
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 进程控制块结构体(增加优先级字段)
typedef struct PCB {
char name[10]; // 进程名
int priority; // 优先级(新增)
int required_time; // 要求运行时间
int used_time; // 已运行时间
char state; // 状态(R:就绪, E:结束)
struct PCB* next; // 指向下一个PCB的指针
} PCB;
// 全局变量
PCB* rear = NULL; // 循环队列尾指针
int time_slice = 1; // 时间片长度
int total_processes = 0; // 总进程数
// 函数声明
void createProcesses();
void addToQueue(PCB* newPCB);
void displayQueue();
void runScheduler();
PCB* dequeue();
void enqueue(PCB* pcb);
int main() {
printf("======= 带优先级的时间片轮转调度算法 =======\n");
printf("请输入时间片长度: ");
scanf("%d", &time_slice);
printf("请输入进程数量: ");
scanf("%d", &total_processes);
createProcesses(); // 创建进程并加入循环队列
displayQueue(); // 显示初始队列状态
runScheduler(); // 开始调度执行
printf("\n所有进程已执行完毕!\n");
return 0;
}
// 创建进程并加入循环队列(支持自定义)
void createProcesses() {
for (int i = 0; i < total_processes; i++) {
PCB* newPCB = (PCB*)malloc(sizeof(PCB));
printf("\n=== 进程 %d 信息 ===\n", i+1);
printf("进程名: ");
scanf("%s", newPCB->name);
printf("优先级(1-10): ");
scanf("%d", &newPCB->priority);
printf("要求运行时间: ");
scanf("%d", &newPCB->required_time);
newPCB->used_time = 0;
newPCB->state = 'R'; // 初始状态为就绪
newPCB->next = NULL;
addToQueue(newPCB);
}
}
// 添加新进程到循环队列(按优先级排序插入)
void addToQueue(PCB* newPCB) {
if (rear == NULL) {
// 队列为空
rear = newPCB;
rear->next = rear; // 循环指向自己
} else {
// 按优先级插入到合适位置(优先级高的在前)
PCB* current = rear->next;
PCB* prev = rear;
do {
// 找到第一个优先级低于新进程的位置
if (newPCB->priority > current->priority) {
break;
}
prev = current;
current = current->next;
} while (current != rear->next);
// 插入新进程
prev->next = newPCB;
newPCB->next = current;
// 如果插入在队尾,更新尾指针
if (prev == rear) {
rear = newPCB;
}
}
}
// 显示队列状态
void displayQueue() {
if (rear == NULL) {
printf("队列为空!\n");
return;
}
PCB* current = rear->next; // 从队首开始
PCB* start = current;
printf("\n当前进程队列状态:\n");
printf("进程名\t优先级\t要求时间\t已运行时间\t状态\n");
printf("------------------------------------------------\n");
do {
printf("%s\t%d\t%d\t\t%d\t\t%c\n",
current->name,
current->priority,
current->required_time,
current->used_time,
current->state);
current = current->next;
} while (current != start);
printf("------------------------------------------------\n");
}
// 运行调度器
void runScheduler() {
int time_count = 0; // 时间计数器
while (rear != NULL) {
time_count++;
printf("\n===== 时间片 %d (长度=%d) =====\n", time_count, time_slice);
// 从队首取出一个进程
PCB* current_process = dequeue();
if (current_process == NULL) {
printf("队列为空!\n");
break;
}
printf(">> 执行进程: %s (优先级:%d)\n",
current_process->name,
current_process->priority);
// 运行一个时间片(可能包含多个单位时间)
int remaining_time = current_process->required_time - current_process->used_time;
int actual_slice = (remaining_time < time_slice) ? remaining_time : time_slice;
current_process->used_time += actual_slice;
// 检查进程是否完成
if (current_process->used_time >= current_process->required_time) {
current_process->state = 'E'; // 状态设为结束
printf(" 进程 %s 执行完毕! (总用时: %d)\n",
current_process->name, current_process->used_time);
// 释放完成的进程
free(current_process);
total_processes--;
} else {
// 未完成则重新加入队尾
printf(" 进程 %s 已运行: %d/%d\n",
current_process->name,
current_process->used_time,
current_process->required_time);
enqueue(current_process);
}
// 显示当前队列状态
displayQueue();
// 如果只剩一个进程且已完成,队列可能为空
if (total_processes == 0) {
rear = NULL;
}
}
}
// 从队首取出一个进程
PCB* dequeue() {
if (rear == NULL) {
return NULL; // 空队列
}
PCB* front = rear->next;
if (front == rear) {
// 队列中只有一个元素
rear = NULL;
} else {
// 移除队首元素
rear->next = front->next;
}
return front;
}
// 将进程加入队尾
void enqueue(PCB* pcb) {
if (rear == NULL) {
rear = pcb;
rear->next = rear;
} else {
pcb->next = rear->next;
rear->next = pcb;
rear = pcb; // 更新尾指针
}
}
```
## 代码修改说明
### 1. 添加优先级字段
```c
typedef struct PCB {
// ...
int priority; // 优先级(新增)
// ...
} PCB;
```
### 2. 支持自定义输入
```c
void createProcesses() {
for (int i = 0; i < total_processes; i++) {
// ...
printf("优先级(1-10): ");
scanf("%d", &newPCB->priority);
printf("要求运行时间: ");
scanf("%d", &newPCB->required_time);
// ...
}
}
```
### 3. 按优先级入队
```c
void addToQueue(PCB* newPCB) {
// ...
// 按优先级插入到合适位置(优先级高的在前)
PCB* current = rear->next;
PCB* prev = rear;
do {
if (newPCB->priority > current->priority) {
break;
}
prev = current;
current = current->next;
} while (current != rear->next);
// ...
}
```
### 4. 时间片处理优化
```c
// 运行调度器中的时间片处理
int remaining_time = current_process->required_time - current_process->used_time;
int actual_slice = (remaining_time < time_slice) ? remaining_time : time_slice;
current_process->used_time += actual_slice;
```
## 程序功能演示
```
======= 带优先级的时间片轮转调度算法 =======
请输入时间片长度: 2
请输入进程数量: 3
=== 进程 1 信息 ===
进程名: P1
优先级(1-10): 5
要求运行时间: 4
=== 进程 2 信息 ===
进程名: P2
优先级(1-10): 3
要求运行时间: 6
=== 进程 3 信息 ===
进程名: P3
优先级(1-10): 8
要求运行时间: 3
当前进程队列状态:
进程名 优先级 要求时间 已运行时间 状态
------------------------------------------------
P3 8 3 0 R
P1 5 4 0 R
P2 3 6 0 R
------------------------------------------------
===== 时间片 1 (长度=2) =====
>> 执行进程: P3 (优先级:8)
进程 P3 已运行: 2/3
当前进程队列状态:
进程名 优先级 要求时间 已运行时间 状态
------------------------------------------------
P1 5 4 0 R
P2 3 6 0 R
P3 8 3 2 R
------------------------------------------------
===== 时间片 2 (长度=2) =====
>> 执行进程: P1 (优先级:5)
进程 P1 已运行: 2/4
当前进程队列状态:
进程名 优先级 要求时间 已运行时间 状态
------------------------------------------------
P2 3 6 0 R
P3 8 3 2 R
P1 5 4 2 R
------------------------------------------------
===== 时间片 3 (长度=2) =====
>> 执行进程: P2 (优先级:3)
进程 P2 已运行: 2/6
当前进程队列状态:
进程名 优先级 要求时间 已运行时间 状态
------------------------------------------------
P3 8 3 2 R
P1 5 4 2 R
P2 3 6 2 R
------------------------------------------------
===== 时间片 4 (长度=2) =====
>> 执行进程: P3 (优先级:8)
进程 P3 执行完毕! (总用时: 3)
当前进程队列状态:
进程名 优先级 要求时间 已运行时间 状态
------------------------------------------------
P1 5 4 2 R
P2 3 6 2 R
------------------------------------------------
...(后续调度过程)...
```
## 算法分析
带优先级的时间片轮转调度算法结合了两种调度策略的优点:
1. **时间片轮转**:保证公平性,防止低优先级进程饥饿
2. **优先级调度**:优先处理重要任务,提高系统响应性
该算法的时间复杂度为$O(1)$,空间复杂度为$O(n)$,其中$n$为进程数量。其主要特点包括:
- 高优先级进程获得更多CPU时间
- 每个进程都能在有限时间内获得执行
- 系统响应时间可预测
在实现中,我们采用了按优先级排序的队列插入策略,确保高优先级进程优先执行,同时保留了轮转调度的公平性特点[^1]。