news 2026/6/8 19:25:49

Linux 进程调度机制:CFS 与实时调度的内核实现原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux 进程调度机制:CFS 与实时调度的内核实现原理

Linux 进程调度机制:CFS 与实时调度的内核实现原理

一、进程调度的"公平性"难题:谁该先跑?

Linux 进程调度的核心问题是"公平性"——如何在数百个进程间分配 CPU 时间,既保证交互式进程的响应速度,又不让后台进程饿死。早期的 O(1) 调度器通过优先级数组实现,但在交互式场景下表现不佳——高优先级进程可能独占 CPU,低优先级进程长时间得不到调度。

CFS(Completely Fair Scheduler)从 2.6.23 内核开始成为默认调度器,其核心思想是"完全公平"——每个进程获得的 CPU 时间应该与其权重成正比,通过红黑树维护进程的虚拟运行时间,实现 O(log n) 的调度效率。

二、CFS 调度原理

graph TB subgraph 核心数据结构 A[红黑树<br/>按vruntime排序] --> B[最左节点<br/>vruntime最小=最该运行] B --> C[当前进程<br/>从树中取出运行] end subgraph 调度逻辑 D[时钟中断] --> E[更新当前进程vruntime] E --> F{vruntime > 最左节点?} F -->|是| G[切换到最左节点进程] F -->|否| H[继续运行] end subgraph 公平性保证 I[nice值→权重映射<br/>nice 0=1024] --> J[nice越低权重越高<br/>获得更多CPU时间] J --> K[vruntime增长越慢<br/>越容易被调度] end

CFS 的核心概念是虚拟运行时间(vruntime)。每个进程的 vruntime 按实际运行时间增长,但增长速率与进程权重成反比——高优先级进程的 vruntime 增长慢,低优先级进程增长快。红黑树按 vruntime 排序,调度器总是选择 vruntime 最小的进程运行。

三、CFS 内核实现分析

3.1 核心数据结构

// linux/kernel/sched/fair.c(简化版) struct sched_entity { struct load_weight load; // 进程权重 struct rb_node run_node; // 红黑树节点 u64 vruntime; // 虚拟运行时间 u64 sum_exec_runtime; // 实际运行总时间 }; struct cfs_rq { struct rb_root_cached tasks_timeline; // 红黑树根 unsigned int nr_running; // 运行队列中的进程数 u64 min_vruntime; // 队列最小vruntime struct sched_entity *curr; // 当前运行的进程 };

3.2 vruntime 更新

// 更新当前进程的 vruntime static void update_curr(struct cfs_rq *cfs_rq) { struct sched_entity *curr = cfs_rq->curr; u64 now = rq_clock_task(rq_of(cfs_rq)); u64 delta_exec; if (unlikely(!curr)) return; // 计算实际运行时间 delta_exec = now - curr->exec_start; // 更新实际运行总时间 curr->sum_exec_runtime += delta_exec; // 计算 vruntime 增量:实际时间 × (NICE_0_LOAD / 进程权重) // 高权重进程的 vruntime 增长慢 curr->vruntime += calc_delta_fair(delta_exec, curr); // 更新队列最小 vruntime update_min_vruntime(cfs_rq); } // vruntime 增量计算 static u64 calc_delta_fair(u64 delta, struct sched_entity *se) { if (unlikely(se->load.weight != NICE_0_LOAD)) // 权重 != 1024 时,按比例缩放 delta = __calc_delta(delta, NICE_0_LOAD, &se->load); return delta; }

3.3 进程选择与切换

// 选择下一个运行的进程 static struct sched_entity * pick_next_entity(struct cfs_rq *cfs_rq) { struct sched_entity *se = NULL; // 从红黑树中取最左节点(vruntime 最小) se = rb_entry(cfs_rq->tasks_timeline.rb_leftmost, struct sched_entity, run_node); return se; } // 进程入队 static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se) { rb_add_cached(&se->run_node, &cfs_rq->tasks_timeline, __entity_less); // 按 vruntime 排序 } // 进程出队 static void __dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se) { rb_erase_cached(&se->run_node, &cfs_rq->tasks_timeline); }

3.4 实时调度

// 实时调度策略:SCHED_FIFO 和 SCHED_RR // 实时进程优先级高于普通进程,CFS 只在无实时进程时运行 struct rt_rq { struct rt_prio_array active; // 优先级位图 + 队列数组 unsigned int rt_nr_running; // 实时进程数 }; // SCHED_FIFO:先进先出,不主动让出 CPU 就一直运行 // SCHED_RR:轮转,每个时间片 100ms,用完重新排队 static struct task_struct *pick_next_task_rt(struct rq *rq) { // 从最高优先级的队列中取第一个进程 struct rt_prio_array *array = &rq->rt.active; int idx = sched_find_first_bit(array->bitmap); struct list_head *queue = array->queue + idx; return list_entry(queue->next, struct task_struct, rt); }

四、调度机制的 Trade-offs 分析

CFS 的公平性 vs. 响应性:CFS 保证长期公平,但短期的交互响应可能不如 O(1) 调度器。内核通过"最小粒度"(sched_min_granularity,默认 0.75ms)和"唤醒抢占"机制来改善响应性——新唤醒的交互进程可以抢占当前进程。

实时进程的饿死风险:SCHED_FIFO 实时进程如果不主动让出 CPU,会永久占据 CPU,导致普通进程饿死。Linux 通过 RT throttling 机制限制实时进程的 CPU 占用上限(默认 95%),预留 5% 给普通进程。

红黑树的开销:红黑树的插入和删除是 O(log n),在进程数极多(>10000)时,调度开销不可忽略。但实际系统中运行队列中的进程数通常在几十到几百,O(log n) 的开销可以忽略。

nice 值的非线性映射:nice 值每降低 1,CPU 时间份额增加约 10%,而非线性增长。nice -20 的进程获得的 CPU 时间约为 nice 0 的 10 倍,nice 19 约为 nice 0 的 1/10。这种设计避免了极端优先级导致的严重不公平。

五、总结

CFS 通过红黑树和虚拟运行时间实现了"完全公平"的进程调度——每个进程获得的 CPU 时间与其权重成正比,调度复杂度 O(log n)。实时调度通过优先级位图实现 O(1) 调度,保证实时进程的确定性延迟。两者协同,既保证了普通进程的公平性,又满足了实时进程的确定性要求。

理解 CFS 的关键在于"虚拟运行时间"概念——它将"谁最该运行"的问题转化为"谁的 vruntime 最小"的排序问题,红黑树天然适合这一场景。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/8 19:24:14

JoyCon-Driver:5分钟让Switch手柄在Windows上焕发新生

JoyCon-Driver&#xff1a;5分钟让Switch手柄在Windows上焕发新生 【免费下载链接】JoyCon-Driver A vJoy feeder for the Nintendo Switch JoyCons and Pro Controller 项目地址: https://gitcode.com/gh_mirrors/jo/JoyCon-Driver 想在Windows电脑上免费使用你的任天堂…

作者头像 李华
网站建设 2026/6/8 19:22:27

如何使用PHAR Utils快速创建可重现的PHAR包:Timestamps类完整指南

如何使用PHAR Utils快速创建可重现的PHAR包&#xff1a;Timestamps类完整指南 【免费下载链接】phar-utils PHAR file format utilities, for when PHP phars you up. 项目地址: https://gitcode.com/gh_mirrors/ph/phar-utils 在PHP开发中&#xff0c;创建可重现的PHAR…

作者头像 李华
网站建设 2026/6/8 19:21:53

BMS热插拔防护设计:从MC33771x芯片防护到系统级操作规范

1. 项目概述&#xff1a;为什么BMS的热插拔防护不是“可选项”&#xff1f;在新能源汽车的维修车间里&#xff0c;或者在一个大型储能电站的调试现场&#xff0c;你可能会看到工程师在系统未完全下电的情况下&#xff0c;断开或连接电池采样线束。这种操作&#xff0c;在行业内…

作者头像 李华
网站建设 2026/6/8 19:21:34

Happy Island Designer测试策略:单元测试与集成测试的完整方案

Happy Island Designer测试策略&#xff1a;单元测试与集成测试的完整方案 【免费下载链接】HappyIslandDesigner "Happy Island Designer (Alpha)"&#xff0c;是一个在线工具&#xff0c;它允许用户设计和定制自己的岛屿。这个工具是受游戏《动物森友会》(Animal C…

作者头像 李华
网站建设 2026/6/8 19:21:19

开源开发工具:Mac Mouse Fix让你的鼠标在macOS上焕发新生

开源开发工具&#xff1a;Mac Mouse Fix让你的鼠标在macOS上焕发新生 【免费下载链接】mac-mouse-fix Mac Mouse Fix - Make Your $10 Mouse Better Than an Apple Trackpad! 项目地址: https://gitcode.com/GitHub_Trending/ma/mac-mouse-fix 在macOS生态系统中&#x…

作者头像 李华