基于OS模拟实现的MLFQ (Multi-Level Feedback Queue) 调度

1: 概述

对于操作系统的任何知识都不应该止于笔而应该动于行

MLFQ (Multi-Level Feedback Queue) 在全网的搜索中大多都是理论上的 这在操作系统调度方向的设计原理是远远不够的。

MLFQ的规则

(1)A的优先级>B的优先级,运行A

(2)A的优先级=B,轮转运行

存在的问题:低优先级的进程永无机会运行。

改变优先级: (3)工作进入系统时,放入最高优先级

(4a)工作用完整个时间片后,降低优先级

(4b)若工作在其时间片内主动释放CPU,其优先级不变

话少说些,代码多些,如果对MLFQ不了解的可以先去理解下理论 基于C语言实现 Git: github.com/mianTanKnig...

面临的问题:

1: Cpu 时间片单位 2: 高效的MLFQ 设计(包括升降级与轮询) 3: 任务的随机性(包括任务随机准备好和运行时任务的随机生成,就像真实的操作系统面临的问题) 4: BadTask的支持(一种长期占用最高优先度队列的任务,通常是在时间片最后一次触发IO) 2: 使用PPE(周期性优先级提升) 解决任务饥饿问题

设计思路

  • 队列的优先级调度: 我们实现了一个由多个优先级队列组成的调度器。每个队列代表一个优先级,优先级越高,队列中的任务越先被调度执行。
  • 时间片轮询与任务降级 : 每个任务会被分配一个时间片,时间片内如果任务无法完成,则降级到更低的优先级队列中。这样我们实现了时间片轮询任务降级的机制,从而模拟了操作系统中的多级反馈队列。
  • 队列中的任务轮询: 每个队列的任务采用**轮询(Round Robin)**的方式调度,即每个任务都会按照顺序获得它的时间片,从而实现公平调度。
  • 注册队列与动态任务 : 我们设计了一个单独的注册队列 ,用于管理新加入的任务。这些任务会在满足条件时进入调度队列,这种设计模拟了任务动态到达的情形,体现了调度器的灵活性

Task的设计

设计思想: remaining_cpu_time: 任务的所需的时间片长

seed: 随即种子 它是每次调度执行时参与rand() 来控制是否产生IO

cpu_io_ratio: 0.1- 1 。与seed生成伪随机算法是否击中IO

arrival_time: 在创建时并没有准备好 而是在被调度时才准备好 这个值是创建时间随机生成

io_trigger_points :操作系统在轮询时会给予一定的时间片时 例如 10 t io_trigger_points[0] - io_trigger_points[1] 是控制IO发生的区域

测试用 execute_task 它只是用于测试Task

更多的测试

Timer:

Queue

queue只是个双向链表

Mlfq

Core Code:

核心设计思想:

双队列设计 -> 注册队列+ MLFQ

注册队列中的value是 MLFQ中节点指针的指针

MLFQ中节点的节点会频繁的移动 但注册队列是用支持整个调度进度和生命管理( MLFQ中节点的在完成时只会移除队列 而非销毁 销毁是和注册队列挂钩 )

双队列设计: 注册队列 + MLFQ

我们在 MLFQ(多级反馈队列)调度系统中采用了双队列设计,包括注册队列和多级反馈队列(MLFQ)。这种设计有助于实现对任务的生命周期管理和调度的灵活性。

注册队列 是一个用于支持整个任务调度进度和生命周期管理的队列。注册队列中的每个节点指针实际上指向 MLFQ 中节点的指针,这意味着它保存的是任务在 MLFQ 中节点的引用。这种指针的指针设计允许我们在 MLFQ 中的节点频繁移动时,保持注册队列对任务的追踪和管理。

注册队列的一个关键特点是,任务在 MLFQ 中被调度、移动或重新插入时,任务节点并不会从注册队列中移除,而只是从当前的优先级队列中移动。当一个任务完成时,才会从注册队列中移除并销毁。这意味着 MLFQ 中的节点完成任务时,只是从当前优先级队列中移除,并不会立即销毁。销毁的控制由注册队列来实现,这样可以保证任务的完整生命周期管理。

MLFQ(多级反馈队列) 是由多个优先级队列组成,用于实现任务的调度和优先级管理。任务在这些优先级队列中移动,以便对不同优先级的任务进行调度和管理。例如,高优先级任务会优先得到调度,而低优先级的任务则可能因为没有合适的调度机会而逐渐被降级。

核心调度思想

核心的调度思想是基于 MLFQ 的多级反馈机制,通过时间片的轮询来实现公平的任务调度。在每一轮调度中,每个优先级队列中的任务都会按照顺序执行,直至它们的时间片用尽。

在调度过程中,使用队列的数据结构特性来实现任务的自然轮询。例如,对于同一级别的任务队列,任务 A 执行后,如果未完成则重新入队,顺序自然变为 B、C、D、A,这样保证了同一级别的任务能得到公平调度。

在 MLFQ 的调度过程中,任务可能由于长时间未主动释放 CPU 而被降级到更低优先级队列。而如果任务在时间片用尽前释放 CPU,则会保留当前优先级。

解决饥饿问题

我们采用了一种 周期性优先级提升机制 来解决低优先级任务可能因长期等待而发生饥饿的问题。这个机制是基于操作系统中的优先级老化思想,即当一个任务在最低优先级队列中等待超过特定时间时,会将其提升至更高优先级,以便获得更多的调度机会。

在我们的实现中,每隔一定的时间(例如 500 个时间片),系统会扫描 MLFQ 中的低优先级队列。如果发现某个任务等待的时间超过设定阈值,就会将其从当前优先级队列移除,提升其优先级并重新插入到更高优先级的队列中。这种周期性优先级提升机制简单而有效,适合教学和理解操作系统调度算法的核心思想,同时可以严谨地模拟操作系统中如何防止任务饥饿的情况。

通过双队列的设计,我们能够更好地管理任务的生命周期,保持任务的状态一致性,同时确保调度的灵活性和高效性。MLFQ 中的核心调度思想基于时间片轮询和优先级管理,结合周期性的优先级提升机制,有效地模拟了操作系统中的调度过程,确保了公平性和防止任务饥饿的发生。

相关推荐
nurupo1231 分钟前
C++学习路线(二十五)
c++·学习·算法
knoci15 分钟前
【Go】-基于Gin框架的博客项目
后端·学习·golang·gin
LNTON羚通1 小时前
算法定制LiteAIServer视频智能分析平台裸土检测技术实现、应用场景与优势概览
大数据·算法·目标检测·音视频·监控
Xiaoyu Wang2 小时前
Go语言八股(Ⅲ)
开发语言·后端·golang
Ruoyo1762 小时前
【Flask框架】10、Flask项目拆分规范
后端·python·flask
Loong_DQX2 小时前
[flask] flask-mail邮件发送
后端·python·flask
hummhumm2 小时前
Oracle 第13章:事务处理
开发语言·数据库·后端·python·sql·oracle·database
书鸢12362 小时前
力扣每日一题合集
java·算法·leetcode
我不会JAVA!3 小时前
排序算法(3) C++
c++·算法·排序算法
Willliam_william3 小时前
SystemC学习(3)— APB_SRAM的建模与测试
学习·算法