操作系统实验四——多级反馈队列调度算法
实验要求
多级反馈队列**(****Multi-leveled feedback queue)**调度算法
按以下要求实现多级反馈队列调度算法:假设有5个就绪队列,它们的优先级分别为1,2,3,4,5,它们的时间片长度分别为10ms,20ms,40ms,80ms,160ms,即第i个队列的优先级比第i-1个队列要低一级,但是时间片比第i-1个队列的要长一倍。调度算法包括四个部分:主程序main,进程产生器generator,进程调度器函数scheduler,进程运行器函数executor。
(1) 主程序:设置好多级队列以及它们的优先级、时间片等信息;创建两个信号量,一个用于generator和executor互斥的访问第1个运行队列(因为产生的新进程都是先放到第1个队列等待执行),另一个用于generator和scheduler的同步(即,仅当多级队列中还有进程等待运行时,scheduler才能开始执行调度)。创建进程产生器线程,然后调用进程调度器。
(2) 进程产生器generator****:用线程来实现进程产生器。每隔一个随机的时间段,例如[1,100]ms之间的一个随机数,就产生一个新的进程,创建PCB并填上所有的信息。注意,每个进程所需要运行的时间neededTime在一定范围内(假设为[2,200]ms)内由随机数产生,初始优先级为1。PCB创建完毕后,将其插入到第1个队列进程链表的尾部(要用到互斥信号量,因为executor有可能正好从第1个队列中取出排在队列首的进程来运行)。插入完毕后,generator调用Sleep函数卡睡眠等待随机的一个时间间隔(例如在[1,100**]范围产生的1个随机数****)**,然后再进入下一轮新进程的产生。当创建的进程数量达到预先设定的个数,例如20个,generator就执行完毕退出。
(3) 进程调度器函数scheduler:在该函数中,依次从第1个队列一直探测到第5个队列,如果第1个队列不为空,则调用执行器executor来执行排在该队列首部的进程。仅当第i号队列为空时,才去调度第i+1个队列的进程。如果时间片用完了但是执行的进程还没有完成(即usedTime<neededTime),则调度器把该进程移动到下一级队列的尾部。当所有的进程都执行完毕,调度器退出,返回主程序。
(4) 进程执行器executor:根据scheduler传递的队列序号,将该队列进程链表首部的PCB取出,分配该队列对应的时间片给它运行(我们用Sleep函数,睡眠时间长度为该时间片,以模拟该进程得到CPU后的运行期间)。睡眠结束后,所有队列中的进程的等待时间都要加上该时间片。注意,在访问第1个队列时,要使用互斥信号量,以免跟进程产生器generator发生访问冲突。
实现思路:
假设五个就绪队列,它们的优先级为12345,其实数组索引就决定了优先级的顺序。这里考虑创建一个队列数组,然后根据索引,算出对应的时间即可。
队列用C++STL中的deque实现,这个数据结构有队列的性质,同时也具备遍历的功能,十分强大。
调度算法包含四个部分:main、进程产生器generator、进程调度器scheduler、进程运行器executor。main函数主要是信号量的设置和相关结构体的初始化,这里信号量设计mutex作为generator和executor第一个运行队列的互斥访问信号量;tongbu设置为generator和scheduler先后顺序的信号量;再来一个信号量mutex_sche进行对scheduler线程间操作临界资源的保护。其他基本上按照题目一一对应。
另外,信号量、线程和调度队列存储在一个结构体内,方便传参与管理
1 | struct SIG { |
遇到问题:
- 我们这里创建了两个函数的线程,这样才能实现产生进程和调度进程并行的效果。但是要注意,等待所有线程执行完毕的线程数组,要接收的是调度器的返回值。不然只是产生玩进程直接返回并不是我们先要的效果
- for循环内(短时间一秒钟内)随机数相同的问题,这里用了srand(time(NULL))初始化种子,但是time函数的单位是秒。我们解决方法要么用sleep函数睡眠将近一秒钟的时间,要么用clock()函数,其单位是毫秒。这里采用clock,同时不影响速率。
- 调度时只采用了一层循环。这样并不能满足我们需要调度进程的流程,我们进程调度的流程是,按照优先级顺序判断是否有进程就绪,有则从队列头部取出进程,然后执行,执行完毕则删除头部的进程,否则移动至下一优先级进程,然后继续判断有无进程; 如果无则去往下一优先级的队列。
实验代码:
1 |
|