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

相关推荐
用户0099383143015 分钟前
代码随想录算法训练营第十三天 | 二叉树part01
数据结构·算法
shinelord明9 分钟前
【再谈设计模式】享元模式~对象共享的优化妙手
开发语言·数据结构·算法·设计模式·软件工程
დ旧言~15 分钟前
专题八:背包问题
算法·leetcode·动态规划·推荐算法
goTsHgo19 分钟前
在 Spring Boot 的 MVC 框架中 路径匹配的实现 详解
spring boot·后端·mvc
waicsdn_haha31 分钟前
Java/JDK下载、安装及环境配置超详细教程【Windows10、macOS和Linux图文详解】
java·运维·服务器·开发语言·windows·后端·jdk
_WndProc33 分钟前
C++ 日志输出
开发语言·c++·算法
Q_192849990641 分钟前
基于Spring Boot的摄影器材租赁回收系统
java·spring boot·后端
良许Linux1 小时前
0.96寸OLED显示屏详解
linux·服务器·后端·互联网
努力学习编程的伍大侠1 小时前
基础排序算法
数据结构·c++·算法
求知若饥1 小时前
NestJS 项目实战-权限管理系统开发(六)
后端·node.js·nestjs