一、实验目的

    深刻理解动态优先权调度思想。

 

二、实验内容

    模拟实现动态高优先权优先的调度。要求优先权值高者优先调度运行一个时间片,同优先权按时间顺序。

   

    数据结构:

       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;
}

输入文件测试用例:

操作系统 动态优先权进程调度实验 记录分享_测试数据

四、实验结果

操作系统 动态优先权进程调度实验 记录分享_实验_02

操作系统 动态优先权进程调度实验 记录分享_测试数据_03

操作系统 动态优先权进程调度实验 记录分享_时间片_04

操作系统 动态优先权进程调度实验 记录分享_2d_05

操作系统 动态优先权进程调度实验 记录分享_2d_06

五、实验总结

通过本次《操作系统》课程中的进程调度实验,我深刻理解了动态优先权调度的原理和实现方法。实验中,我模拟了动态高优先权优先的调度过程,实现了进程优先级的动态调整以及就绪队列和完成队列的管理。

在编写代码的过程中,我遇到了不少挑战,特别是在实现按照优先权排序和先来后到排序的插入函数时。但通过反复调试和修改,我最终成功实现了这些功能。

通过本次实验,我不仅提高了编程能力,还加深了对操作系统进程调度机制的理解。我认识到,在实际应用中,进程调度策略的选择对于系统性能至关重要。同时,我也体会到了编程实践对于理论学习的促进作用。

总的来说,这次实验让我收获颇丰,不仅锻炼了我的实践能力,还增强了我对操作系统课程的兴趣。未来,我将继续深入学习相关知识,为未来的学习和工作打下坚实的基础。