2024年末《操作系统》课程设计大作业 模拟进程调度
对 N 个进程应用模拟五种不同的进程调度算法,包括先来先服务(FCFS)、短进程优先(SJF)、时间片轮转(RR)、高响应比优先(HRRN)、动态优先级调度(PR)。
每个进程通过进程控制块(PCB)来标识,PCB 的结构包含以下字段:(a) 进程标识数 ID;(b) 进程到达时间ARRIVETIME;(c) 进程优先级 PRIORITY;(d) 进程运行总时间 ALLTIME;(e) 进程已运行时间 CPUTIME;(f) 进程等待时间 Wait_Time;(g) 进程响应比 Res_Ratio;(h) 进程状态STATE。在动态优先级调度算法中,优先数的调整规则为:进程在就绪队列中每等待一个时间片,优先数增加 1;每运行一个时间片,优先数减少 3。为了观察进程的调度过程,程序需要显示每个时间片内各进程的状态,包括正在运行的进程、在就绪队列中的进程以及在阻塞队列中的进程,以反映进程的就绪态、执行态和阻塞态。
源代码github链接:
https://github.com/yaqli-1024/process-scheduling-algorithm
一、数据结构设计
1、进程控制块(PCB)结构体
PCB 结构体是这段代码的核心数据结构,用于存储进程的相关信息:
(1)ProcessId:进程的唯一标识符。
(2)ARRIVETIME:进程到达系统的时间。
(3)PRIORITY:进程的优先级,数值越大表示优先级越高。
(4)ALLTIME:进程需要的总 CPU 时间。
(5)CPUTIME:进程已经占用的 CPU 时间。
(6)Wait_Time:进程在就绪队列中等待的时间。
(7)Res_Ratio:进程的响应比,用于高响应比优先调度算法。
(8)STATE:进程的当前状态(就绪态、运行态、阻塞态)。
PCB 结构体还包含两个构造函数:一个默认构造函数将所有成员变量初始化为 0,另一个带参数的构造函数允许初始化特定的成员变量。
2、排序函数
提供了多个排序函数,用于不同的进程调度算法:
(1)SortPCB_ARRIVETIME:按进程到达时间排序,用于先来先服务(FCFS)算法。
(2)SortPCB_ALLTIME:按进程所需 CPU 时间排序,用于短进程优先(SJF)算法。
(3)SortPCB_PRIORITY:按进程优先级排序,用于动态优先级调度(PR)算法,如果优先级相同,则按到达时间排序。
(4)SortPCB_Res_Ratio:按进程响应比排序,用于高响应比优先(HRRN)算法。
3、链表节点(Node)结构体
Node 结构体用于构建链表,每个节点包含一个 PCB 数据和一个指向下一个节点的指针pNext。它有两个构造函数:一个默认构造函数和一个带参数的构造函数。
4、链表(NodeList)类
NodeList 类用于管理进程控制块的链表,包含以下功能:
(1)构造函数:初始化链表。
(2)拷贝构造函数:复制链表。
(3)析构函数:销毁链表,释放内存。
(4)isEmpty:检查链表是否为空。
(5)getLength:获取链表长度。
(6)get_X_PCB:获取链表中特定位置的 PCB。
(7)get_X_Node:获取链表中特定位置的 Node。
(8)Print:打印链表中的所有 PCB 数据。
(9)InsertData:在链表中插入数据,可选择是否重新排序。
(10)Delete_X_PCB:删除链表中特定位置的 PCB。
(11)SortList:根据设置的比较函数对链表进行排序。
(12)ComparePCB:设置用于排序的比较函数。
(13)getHeadNode:获取链表的头节点。
二、算法设计
使用自然语言对算法进行描述
1、先来先服务算法(FCFS)
(1)算法首先检查传入的进程链表是否为空。如果不为空,按照进程的到达时间对链表进行排序。
(2)在 realize 方法中,初始化当前时间为 0。
(3)在一个循环中处理队列中的每个进程。首先执行队列中的第一个进程。
(4)对于每个进程,如果它的到达时间大于当前时间,算法会等待直到该进程到达。
(5)一旦进程到达,将其状态设置为执行态。
(6)从就绪队列中删除该进程。
(7)执行该进程直到完成,并更新当前时间。
(8)在每个时间片内输出当前执行的进程和就绪队列的状态。
(9)完成进程执行后,输出已完成的进程信息。
(10)挑选出当前就绪队列中第一个进程并执行,跳转至第 4 步。
(11)如果链表为空,则输出提示信息并结束。
2、短进程优先算法(SJF)
(1)首先检查传入的进程链表是否为空。如果不为空,按照进程的到达时间(ARRIVETIME)对链表进行排序。
(2)在 realize 方法中,初始化当前时间为 0。创建一个空的就绪队列 ready_List,用于存储在当前时间内到达但尚未执行的进程。从进程链表中提取第一个进程 p,并按照到达时间进行调度。
(3)进入主循环:在一个循环中,处理链表中的每个进程,直到主链表和就绪队列均为空。
(4)如果当前时间 now 小于第一个进程的到达时间 p.ARRIVETIME:系统进入空闲状态,输出“当前无进程执行”的状态,同时打印当前时间片内的就绪队列状态(可能为空)。将当前时间now 更新为第一个进程的到达时间 p.ARRIVETIME。
(5)执行当前进程:将当前进程 p 的状态设置为“执行态”(STATE = 1),并开始运行该进程。在执行时间段内,记录每个时间片的状态。
(6)更新就绪队列:遍历主链表,将到达时间在 [ARRIVETIME, ARRIVETIME + ALLTIME]范围内的新进程加入就绪队列。确保只将不在就绪队列中的进程加入,避免重复。将这些进程按照执行时间进行排序。
(7)当前进程完成后,从主链表中删除已完成的进程 p,并输出完成信息。将当前时间 now更新为 now + p.ALLTIME。
(8)如果就绪队列非空,选择执行时间最短的进程作为下一个调度对象。当主链表和就绪队列均为空时,调度循环结束,算法执行完毕。
3、时间片轮转调度算法(RR)
(1)初始化:创建 RR 类实例时,算法首先检查传入的进程链表是否为空。如果不为空,根据进程到达时间(ARRIVETIME)对链表进行排序,并调用 SortList 函数完成初始化。
(2)创建一个空的就绪队列 ready_List,用于存储当前时间之前到达且尚未完成的进程。就绪队列中的进程按照到达时间排序。
(3)进入主循环:主循环依次处理所有未完成的进程,直到主链表和就绪队列均为空。
(4)遍历主链表,将到达时间小于或等于当前时间 now 的进程加入就绪队列,并从主链表中删除这些进程。将被添加的进程状态设置为“就绪态”(STATE = 0)。
(5)处理空闲时间:如果就绪队列为空,检查主链表中是否还有未到达的进程。如果存在未到达的进程,则跳到下一个进程的到达时间,并记录期间的系统空闲状态。
(6)从就绪队列中取出第一个进程,设置其状态为“执行态”(STATE = 1)。执行当前进程一个时间片(长度为 1)。记录当前时间片的状态,增加当前时间 now 并更新进程的已执行时间 CPUTIME。
(7)检查进程是否完成:如果当前进程的已执行时间 CPUTIME 小于总需执行时间ALLTIME,则将其状态设置为“就绪态”(STATE = 0),并将其重新加入到就绪队列末尾。如果当前进程已完成,则输出该进程的完成信息,不再将其放回就绪队列。
(8)继续处理下一时间片。如果就绪队列不为空,则从中取出下一个进程,重复步骤 6 和7。如果就绪队列为空,但主链表中仍有未到达的进程,则跳到下一个到达的进程时间,重复步骤 4 和 5。
(9)当主链表和就绪队列均为空时,调度循环结束,算法执行完毕。
4、高响应比优先算法(HRRN)
(1)初始化:构造一个进程列表(list),其中的进程按照到达时间 (ARRIVETIME) 进行排序。设置一个空的就绪队列(ready_List),以便在调度时存放待执行的进程。就绪队列的排序依据为进程的响应比 (Res_Ratio),高响应比优先。
(2)检查进程列表是否为空。若非空,获取进程列表中第一个到达的进程,将其状态设置为“执行态”(STATE=1),并记录当前时间为 now。
(3)检查是否有进程在当前执行进程的执行时间范围内到达(即 ARRIVETIME 在 [now, now + ALLTIME] 内)。将符合条件且未在就绪队列中的进程加入到就绪队列。如果当前时间未达到下一个进程的到达时间,系统会等待。此时,输出每个空闲时间片的状态。
(4)执行当前进程,更新当前时间 now 和进程的完成状态。输出每个执行时间片的状态。
(5)执行完成的进程将从队列中移除。对就绪队列中的每个进程,计算其等待时间(Wait_Time) 和响应比 (Res_Ratio)。响应比计算公式为:响应比 = (等待时间 + 要求服务时间) / 要求服务时间。按照响应比对就绪队列进行排序。
(6)从就绪队列中选取响应比最高的进程进行执行,设置为“执行态”(STATE=1)。如果就绪队列为空,则从 list 中提取下一个到达的进程进行调度。
(7)当 list 和 ready_List 均为空时,算法结束。
5、动态优先级调度算法(PR)
(1)初始化:所有进程根据到达时间(ARRIVETIME)排序,并存储在一个主队列中,称为 list。同时,定义一个初始为空的就绪队列 ready_List,按照优先级进行排序,用于存放已到达但尚未执行的进程。每个进程的初始优先级被设为 50,时间片大小固定为 1。
(2)从 ready_List 中取出优先级最高的进程进行执行(根据当前优先级排序,优先级越高值越大)。当前进程的状态设置为“执行态”(STATE=1),并执行一个时间片或直到其完成所需的剩余时间(取两者的最小值)。
(3)更新优先级:当前执行的进程优先级每执行一个时间片减少 3。所有其他就绪队列中的进程优先级每经过一个时间片增加 1。
(4)如果当前执行进程的 CPU 时间达到总执行时间(ALLTIME),则标记为完成,并从调度中移除。否则,将其重新加入就绪队列末尾,状态标记为“就绪态”(STATE=0)。
(5)每次时间片结束后,重新根据优先级对就绪队列进行排序,确保优先级最高的进程在下次时间片优先执行。
(6)在就绪队列中挑选出优先级最高的进程执行,重复 2——6 步。
(7)当主队列 list 和就绪队列 ready_List 均为空时,说明所有进程均已完成执行,算法结束。
6、系统测试代码(main)
通过输入数字来选择一种进程调度算法,运行并查看结果。
三、运行结果展示
1、先来先服务算法(FCFS)
2、短进程优先算法(SJF)
3、时间片轮转调度算法(RR)
4、高响应比优先算法(HRRN)
5、动态优先级调度算法(PR)