因为动态优先级由队列层级决定,时间片耗尽需直接移入下一级队列而非仅减数值;否则退化为单队列调度,丧失多级反馈机制。

多级反馈队列中 decrease_priority() 为什么不能简单减 1
动态优先级不是线性递减,而是按队列层级跳变。比如进程在第 0 级队列(最高优先级)运行一个时间片后未完成,应直接降入第 1 级,而非把优先级值减 1——因为第 1 级的调度时间片更长、抢占更弱。若只改数值不切换队列,就退化成单队列优先级调度。
实操建议:
- 用
queue_level字段显式记录当前所在队列索引(0~N-1),而非仅靠priority数值推导 - 每次时间片耗尽时,执行
move_to_next_queue():检查是否已达最低级,是则保持原队列;否则push_back()到下一级队列尾部 - 避免在
run_process()中修改priority成员变量——它仅用于初始排序或调试打印,真实调度依据是队列位置
如何让低级队列进程不被饿死:aging() 的触发时机和幅度
标准 MFQ 饿死防护靠“老化”(aging):定期将低级队列中等待过久的进程提升到较高级队列。但提升太频繁会削弱多级设计意义,太迟钝又起不到作用。
实操建议:
- 用全局计时器
global_tick记录已执行的总时间片数,每满AGE_INTERVAL = 50个时间片扫描一次所有低级队列(如 level ≥ 2) - 对每个满足
wait_time > AGE_THRESHOLD * (level + 1)的进程,将其移入min(level - 1, 0)队列头部(不是尾部!保证及时响应) - 不要在每次调度前都调用
aging()——它应是低频后台操作,否则严重拖慢主循环
std::vector<:queue>> 还是 std::deque?性能与可读性权衡
多级队列本质是固定层数的队列数组,std::vector 支持 O(1) 层级索引,但 std::queue 底层默认用 std::deque,嵌套后内存局部性差;而全用 std::deque<:deque>> 又增加间接访问开销。
实操建议:
- 定义为
std::vector<:deque>>:兼顾随机访问层级 + 高效首尾操作 - 避免
std::queue包装器——它禁用迭代器且无法获取长度,调试时查queues[level].size()很麻烦 - 若需频繁遍历某级全部进程(如 aging 扫描),
std::deque比std::queue更易迭代
模拟中断和 I/O 阻塞时,process.state 和队列迁移怎么同步
真实系统中,进程因 I/O 进入阻塞态后,唤醒时不应回到原队列尾部,而应恢复到被抢占前的队列层级,并重置其剩余时间片。否则会误判为“已运行很久”,导致不该降级的被降级。
实操建议:
- 给
Process结构体加字段:int original_level(创建/唤醒时记录)、int remaining_quantum(每级独立维护) - I/O 请求发生时,将进程从当前队列移出,插入到
blocked_queue(单独的std::queue),不改变original_level - 唤醒时,根据
original_level插入对应队列头部,并恢复该级预设的quantum值(如 level 0 → 4ms,level 1 → 8ms) - 切忌在阻塞/唤醒路径中调用
move_to_next_queue()——那是 CPU 耗尽专属逻辑
MFQ 模拟最难的不是结构搭建,而是各级之间状态迁移的边界条件:时间片耗尽、I/O 中断、老化提升、新进程插入,四者触发的队列操作不能互相覆盖。建议先用打印日志把每个迁移动作打出来,确认 process.id、level、remaining_quantum 三者变化严格符合预期,再关掉日志跑性能测试。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











