一、实验目的
深刻理解动态优先权调度思想。
二、实验内容
模拟实现动态高优先权优先的调度。要求优先权值高者优先调度运行一个时间片,同优先权按时间顺序。
数据结构:
Struct PCB{
Int PID; --进程编号
Int Pri; --优先权
Int Ptime; --运行时间
*Next; --队列指针
}
指针:
Struct PCB *ReadyH;
Struct PCB *FinishH;
Struct PCB *CurP;
待实现功能:
InsertRQ(*); --按照优先权排序
InsertFQ(*); --按照先来后到排序
Schedule(); --调度,RQ->CurP
RunASlice(); --运行1时间,空函数
DisplayRQ(); --显示就绪队列信息
DisplayFQ(); --显示完成队列信息
步骤:
1. 初始化就绪队列;
2. While RQ不为空
(1)调度进程;
(2)运行一个时间片;
(3)当前进程时间-1;
当前进程优先权-3;
(4)时间为0,InsertFQ;
否则,InsertRQ;
要求:
(1)测试数据可以随机输入或从文件中读入;
(2)计算每一个进程的周转时间、带权周转时间;
(3)可以展示某个时刻的RQ和FQ的进程信息;
(4)记录每一时间片后RQ和FQ的进程信息。
三、实验代码
#include <stdio.h>
#include <stdlib.h>
// 进程控制块 PCB
struct PCB {
int PID; // 进程编号
int Pri; // 优先权
int Ptime; // 运行要求时间
int PtimeRun; //运行过程时间
int ArrivalTime; // 到达时间
int FinishTime; // 完成时间
int TurnaroundTime; // 周转时间
float WeightedTurnaroundTime; // 带权周转时间
struct PCB *Next; // 队列指针
};
// 全局变量
struct PCB *ReadyH = NULL; // 就绪队列头指针
struct PCB *FinishH = NULL; // 完成队列头指针
struct PCB *CurP = NULL; // 当前运行进程指针
int currentTime = 0; // 当前时间
// 插入就绪队列,按照优先权排序
void InsertRQ(struct PCB *newPCB) {
struct PCB *prev = NULL;
struct PCB *curr = ReadyH;
if(newPCB->PtimeRun > 0){
while (curr != NULL && curr->Pri >= newPCB->Pri) {
prev = curr;
curr = curr->Next;
}
}
if (prev == NULL) {
newPCB->Next = ReadyH;
ReadyH = newPCB;
} else {
prev->Next = newPCB;
newPCB->Next = curr;
}
}
// 插入完成队列,按照先来后到排序
void InsertFQ(struct PCB *newPCB) {
newPCB->FinishTime = currentTime+1;
if (FinishH == NULL) {
FinishH = newPCB;
newPCB->Next = NULL;
} else {
struct PCB *curr = FinishH;
while (curr->Next != NULL) {
curr = curr->Next;
}
curr->Next = newPCB;
newPCB->Next = NULL;
}
}
// 调度,从就绪队列中选取优先权最高的进程运行
void Schedule() {
if (ReadyH != NULL) {
CurP = ReadyH;
ReadyH = ReadyH->Next;
CurP->Next = NULL;
} else {
CurP = NULL;
}
}
// 运行一个时间片
void RunASlice() {
if (CurP != NULL) {
printf("Running process with PID %d for one time slice.So it`s Pri - 3 and PtimeRun - 1.\n", CurP->PID);
if(CurP->Ptime == CurP->PtimeRun)
CurP->ArrivalTime = currentTime;
CurP->PtimeRun--; // 减少剩余运行时间
CurP->Pri -= 3; // 减少优先级
if (CurP->PtimeRun <= 0) {
CurP->FinishTime = currentTime+1; // 设置完成时间
InsertFQ(CurP); // 如果进程运行完毕,插入完成队列
CurP = NULL;
} else {
InsertRQ(CurP); // 否则重新插入就绪队列
}
} else {
printf("No process to run.\n\n");
}
}
// 计算周转时间和带权周转时间,并显示
void CalculateTurnaroundTime(struct PCB *pcb) {
pcb->TurnaroundTime = pcb->FinishTime - pcb->ArrivalTime;
pcb->WeightedTurnaroundTime = (float) pcb->TurnaroundTime / pcb->Ptime;
// 展示周转时间和带权周转时间
printf("Process with PID %d: Turnaround Time: %-2d, Weighted Turnaround Time: %.2f\n",
pcb->PID, pcb->TurnaroundTime, pcb->WeightedTurnaroundTime);
}
// 显示就绪队列信息
void DisplayRQ() {
printf("Ready Queue:\n");
struct PCB *curr = ReadyH;
while (curr != NULL) {
printf("\tPID: %d, Pri: %d, PtimeRun: %d\n", curr->PID, curr->Pri, curr->PtimeRun);
curr = curr->Next;
}
}
// 显示完成队列信息
void DisplayFQ() {
printf("Finish Queue:\n");
struct PCB *curr = FinishH;
while (curr != NULL) {
printf("\tPID: %d, EndPri: %-3d, Ptime: %-2d, FinishTime: %2d, ArrivalTime: %d\n",
curr->PID, curr->Pri, curr->Ptime, curr->FinishTime, curr->ArrivalTime);
curr = curr->Next;
}
}
// 读取测试数据
void ReadTestData() {
FILE *file = fopen("test_datas.txt", "r");
if (file == NULL) {
perror("Error opening file");
exit(1);
}
while (!feof(file)) {
struct PCB *newPCB = (struct PCB *)malloc(sizeof(struct PCB));
if (fscanf(file, "%d %d %d", &(newPCB->PID), &(newPCB->Pri), &(newPCB->Ptime)) != 3) {
free(newPCB);
break;
}
newPCB->PtimeRun = newPCB->Ptime;
newPCB->ArrivalTime = 0;
newPCB->FinishTime = -1; // Initialize finish time
newPCB->TurnaroundTime = -1; // Initialize turnaround time
newPCB->WeightedTurnaroundTime = -1.0f; // Initialize weighted turnaround time
newPCB->Next = NULL;
InsertRQ(newPCB);
}
fclose(file);
}
int main() {
ReadTestData(); // 读取测试数据
// 测试调度和运行
while (ReadyH != NULL || CurP != NULL) {
printf("Time: %d\n", currentTime);
DisplayFQ();DisplayRQ();
Schedule();
RunASlice();
currentTime++;
printf("\n");
}
printf("Time: %d\n", currentTime);
DisplayFQ();DisplayRQ();
RunASlice();
// 为每一个进程计算和展示周期时间和带权周期时间
struct PCB *curr = FinishH;
while (curr != NULL) {
CalculateTurnaroundTime(curr);
curr = curr->Next;
}
return 0;
}
输入文件测试用例:
四、实验结果
五、实验总结
通过本次《操作系统》课程中的进程调度实验,我深刻理解了动态优先权调度的原理和实现方法。实验中,我模拟了动态高优先权优先的调度过程,实现了进程优先级的动态调整以及就绪队列和完成队列的管理。
在编写代码的过程中,我遇到了不少挑战,特别是在实现按照优先权排序和先来后到排序的插入函数时。但通过反复调试和修改,我最终成功实现了这些功能。
通过本次实验,我不仅提高了编程能力,还加深了对操作系统进程调度机制的理解。我认识到,在实际应用中,进程调度策略的选择对于系统性能至关重要。同时,我也体会到了编程实践对于理论学习的促进作用。
总的来说,这次实验让我收获颇丰,不仅锻炼了我的实践能力,还增强了我对操作系统课程的兴趣。未来,我将继续深入学习相关知识,为未来的学习和工作打下坚实的基础。