Linux 内核调度基础:CFS 调度器原理、时间片与优先级、内核抢占点、中断上下文与进程上下文

在深入 PREEMPT_RT 的配置调优之前,必须牢固掌握 Linux 内核调度的核心基础。实时性优化的本质是减少调度延迟,而调度延迟的根源就藏在这些基础机制中。本章将拆解 CFS 调度器、时间片与优先级、内核抢占点以及上下文切换这四个关键模块。

2.1 CFS 调度器原理

完全公平调度器(CFS,Completely Fair Scheduler)是 Linux 内核默认的调度器,设计目标是让每个进程获得公平的 CPU 时间。CFS 不直接分配时间片,而是引入虚拟运行时间(vruntime)的概念。

  • vruntime:进程实际运行时间经过优先级加权后的值。优先级越高(nice 值越小),vruntime 增长越慢。
  • 红黑树:CFS 将所有可运行进程按 vruntime 排序,最左侧节点(vruntime 最小)就是下一个被调度的进程。
  • 目标延迟:CFS 期望在一个调度周期内,所有可运行进程至少被调度一次。默认值通常为 6ms 到 24ms 之间。
  • 最小粒度:进程每次运行的最小时间,默认 1ms,防止频繁上下文切换导致开销过大。
实时调优提示: 在 PREEMPT_RT 环境中,CFS 的公平性机制可能成为实时任务的干扰源。通过调整 sched_min_granularity_ns 和 sched_latency_ns 内核参数,可以压缩非实时任务的调度周期,为实时任务让路。
CFS 调度器核心结构 红黑树根 vruntime 最小 vruntime 较大 进程 A 进程 B 进程 C 进程 D 调度决策:每次从红黑树最左节点取出进程运行,运行后更新 vruntime 并重新插入树中

2.2 时间片与优先级

CFS 没有传统意义上的固定时间片,而是通过权重(weight)和调度周期动态计算运行时间。优先级通过 nice 值(-20 到 +19)体现,数值越小优先级越高。

nice 值 权重 相对优先级 典型应用场景
-20 88761 最高 实时音频处理、硬实时控制
-10 11051 高 交互式应用、前台进程
0 1024 默认 普通用户进程
10 304 低 后台批处理任务
19 15 最低 空闲任务、低优先级计算

进程实际获得的运行时间计算公式:

进程运行时间 = 调度周期 × (进程权重 / 所有可运行进程权重之和)
关键点: 在 PREEMPT_RT 系统中,实时线程(SCHED_FIFO/SCHED_RR)的优先级范围是 0-99,完全独立于 CFS 的 nice 值。CFS 的优先级机制仅影响非实时进程之间的公平调度。

2.3 内核抢占点

内核抢占点是指内核代码中允许发生进程调度切换的位置。抢占点的密度和位置直接影响系统的调度延迟。Linux 内核支持三种抢占模型:

  • PREEMPT_NONE:无内核抢占,只在返回用户空间时检查调度。
  • PREEMPT_VOLUNTARY:在显式的抢占点(如系统调用返回、锁释放)处允许抢占。
  • PREEMPT_FULL:在大多数内核代码中允许抢占,除了少数临界区。
  • PREEMPT_RT:进一步将自旋锁替换为可抢占的互斥锁,几乎实现完全可抢占内核。
内核抢占点演进对比 PREEMPT_NONE 抢占点:用户态返回 PREEMPT_VOLUNTARY 抢占点:+ 锁释放/系统调用 PREEMPT_FULL 抢占点:+ 大多数内核路径 PREEMPT_RT 抢占点:+ 临界区可抢占 调度延迟对比(典型值) PREEMPT_NONE: 10-100ms PREEMPT_VOLUNTARY: 1-10ms PREEMPT_FULL: 100μs-1ms PREEMPT_RT: 1-100μs
注意: 即使启用 PREEMPT_RT,某些不可抢占区域仍然存在,例如中断处理程序的下半部(softirq)和某些原子上下文。这些区域是调优时需要重点关注的延迟来源。

2.4 中断上下文与进程上下文

理解中断上下文和进程上下文的区别,是分析调度延迟的关键。中断处理程序运行在中断上下文中,不可阻塞、不可睡眠;而普通进程运行在进程上下文中,可以睡眠、可以被调度。

特性 中断上下文 进程上下文
可睡眠 否 是
可被抢占 否(传统) 是(PREEMPT_RT 下)
持有锁 自旋锁 互斥锁/自旋锁
调度延迟影响 直接阻塞高优先级任务 通过优先级抢占间接影响
典型处理时间 微秒级 毫秒级
中断上下文 vs 进程上下文切换流程 用户进程 系统调用(进程上下文) 硬件中断 中断处理程序(中断上下文) 下半部(softirq/tasklet) 延迟关键路径 1. 中断发生时,当前进程被 强制暂停 2. 中断处理程序运行期间, 高优先级任务无法运行 3. 下半部处理完成后,才 能恢复调度 4. PREEMPT_RT 将中断处理 线程化,降低延迟影响
PREEMPT_RT 核心优化: 将中断处理程序转换为内核线程(IRQ threads),使中断上下文变为可抢占的进程上下文。这样,高优先级的实时任务可以在中断处理期间抢占 CPU,大幅降低调度延迟。

2.5 调度延迟的构成

调度延迟(Scheduling Latency)是指从事件触发(如中断、定时器到期)到高优先级任务开始执行的时间间隔。它由以下部分组成:

  1. 中断延迟:从硬件中断发生到 CPU 开始执行中断处理程序的时间。
  2. 中断处理时间:中断处理程序执行的时间,包括上半部和下半部。
  3. 调度决策时间:调度器选择下一个运行进程的时间。
  4. 上下文切换时间:保存当前进程状态、加载新进程状态的时间。

在标准内核中,中断处理时间是不可抢占的,因此成为实时性的主要瓶颈。PREEMPT_RT 通过线程化中断和可抢占内核锁,将不可抢占区域压缩到最小,从而将调度延迟从毫秒级降低到微秒级。