基于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 中的核心调度思想基于时间片轮询和优先级管理,结合周期性的优先级提升机制,有效地模拟了操作系统中的调度过程,确保了公平性和防止任务饥饿的发生。

相关推荐
Estar.Lee2 小时前
查手机号归属地免费API接口教程
android·网络·后端·网络协议·tcp/ip·oneapi
LNTON羚通3 小时前
摄像机视频分析软件下载LiteAIServer视频智能分析平台玩手机打电话检测算法技术的实现
算法·目标检测·音视频·监控·视频监控
2401_857610034 小时前
SpringBoot社团管理:安全与维护
spring boot·后端·安全
哭泣的眼泪4084 小时前
解析粗糙度仪在工业制造及材料科学和建筑工程领域的重要性
python·算法·django·virtualenv·pygame
凌冰_5 小时前
IDEA2023 SpringBoot整合MyBatis(三)
spring boot·后端·mybatis
码农飞飞5 小时前
深入理解Rust的模式匹配
开发语言·后端·rust·模式匹配·解构·结构体和枚举
一个小坑货5 小时前
Rust 的简介
开发语言·后端·rust
Microsoft Word5 小时前
c++基础语法
开发语言·c++·算法
天才在此5 小时前
汽车加油行驶问题-动态规划算法(已在洛谷AC)
算法·动态规划
monkey_meng5 小时前
【遵守孤儿规则的External trait pattern】
开发语言·后端·rust