2. 实时内核基础

Linux 内核的实时能力取决于其抢占模型。抢占模型决定了内核在何种时机、何种开销下能够打断当前执行的任务,转而执行更高优先级的任务。理解不同抢占模型的差异,是进行实时性能调优的基石。

从主线内核到 PREEMPT_RT,抢占模型经历了四个主要阶段:PREEMPT_NONE、PREEMPT_VOLUNTARY、PREEMPT 和 PREEMPT_RT。它们的核心区别在于内核态代码的抢占点密度和临界区长度。

核心概念:抢占延迟 = 中断关闭时间 + 内核临界区长度。抢占模型越激进,临界区越短,系统响应越快,但吞吐量可能下降。

2.1 抢占模型演进与配置

在 Linux 内核编译配置中,通过 Kernel Features 菜单选择抢占模型。下表总结了四种模型的关键特征:

模型名称 配置选项 抢占点密度 适用场景 最坏情况延迟
PREEMPT_NONE CONFIG_PREEMPT_NONE 极低(仅在系统调用返回时) 服务器、批处理、科学计算 高(可达数十毫秒)
PREEMPT_VOLUNTARY CONFIG_PREEMPT_VOLUNTARY 低(在显式调度点处) 桌面、轻度交互系统 中等(毫秒级)
PREEMPT CONFIG_PREEMPT 高(在大多数内核路径中) 嵌入式、软实时、多媒体 较低(亚毫秒级)
PREEMPT_RT CONFIG_PREEMPT_RT 极高(几乎全部内核路径,含中断) 工业控制、航空航天、硬实时 极低(微秒级)
配置检查命令:在运行中的系统上,可以通过 zcat /proc/config.gz | grep PREEMPT 或检查 /boot/config-$(uname -r) 文件来确认当前内核使用的抢占模型。

2.2 模型一:PREEMPT_NONE(无抢占)

这是最原始的 Linux 内核模型,也称为 服务器内核。内核在执行系统调用时,除非显式调用 schedule() 或返回用户空间,否则不会被抢占。这意味着一个低优先级的系统调用可以长时间阻塞高优先级任务。

  • 优点:吞吐量最大化,上下文切换开销最小。
  • 缺点:调度延迟不可预测,最坏情况延迟可能达到几十毫秒。
  • 典型场景:数据库服务器、Web 服务器、批处理作业。
PREEMPT_NONE 抢占模型示意图 任务A(高优先级) 任务B(低优先级)执行系统调用 时间 任务B返回用户空间时才能抢占 高延迟等待

2.3 模型二:PREEMPT_VOLUNTARY(自愿抢占)

此模型在 PREEMPT_NONE 的基础上,在内核代码中显式插入了一些 抢占点(如 cond_resched())。当内核执行到这些点时,会检查是否有更高优先级的任务需要运行。这降低了最坏情况延迟,但并未覆盖所有内核路径。

  • 优点:相比 NONE 模型,交互响应有所改善。
  • 缺点:抢占点不全面,长路径仍可能阻塞。
  • 典型场景:桌面 Linux、通用嵌入式系统。
PREEMPT_VOLUNTARY 抢占模型示意图 任务A(高优先级) 任务B执行系统调用(含 cond_resched() 点) 时间 cond_resched() 抢占点 cond_resched() 抢占点 延迟降低

2.4 模型三:PREEMPT(低延迟桌面/嵌入式)

此模型允许在大多数内核代码路径中发生抢占,只要内核没有持有自旋锁。它通过增加 preempt_count 计数来管理,当计数为 0 时允许抢占。这是许多通用发行版(如 Ubuntu、Fedora)的默认选项。

  • 优点:调度延迟显著降低,适合多媒体和软实时应用。
  • 缺点:自旋锁保护的临界区仍不可抢占,中断上下文不可抢占。
  • 典型场景:音频处理、视频播放、机器人控制。
PREEMPT 抢占模型示意图 任务A(高优先级) 任务B执行系统调用(大部分路径可抢占) 临界区 时间 可抢占点 可抢占点 延迟进一步降低

2.5 模型四:PREEMPT_RT(完全实时抢占)

PREEMPT_RT 是实时 Linux 的基石。它通过以下关键机制实现了几乎完全的可抢占性:

  1. 自旋锁替换:将大部分自旋锁替换为 rt_mutex 支持的 可睡眠锁(sleeping spinlocks)。
  2. 中断线程化:将中断处理程序(尤其是下半部)作为内核线程运行,允许被高优先级任务抢占。
  3. 高精度定时器:使用 hrtimer 提供纳秒级定时精度。
  4. 优先级继承:实现 PI(Priority Inheritance)协议,防止优先级反转。
性能权衡:PREEMPT_RT 将最坏情况延迟降低到微秒级,但代价是吞吐量下降约 5%-15%,上下文切换开销增加。对于非实时负载,不建议启用。
PREEMPT_RT 内核架构与抢占路径 用户空间任务(可被任意高优先级任务抢占) 系统调用接口 / 中断线程化入口 PREEMPT_RT 内核核心 可睡眠锁 中断线程 hrtimer PI协议 硬件(中断控制器、定时器、外设) 几乎全部路径可抢占

2.6 抢占模型对比总结

选择哪种抢占模型,取决于应用对 延迟确定性 和 吞吐量 的权衡。下表从多个维度进行了量化对比:

对比维度 PREEMPT_NONE PREEMPT_VOLUNTARY PREEMPT PREEMPT_RT
最坏情况中断延迟 10-100 ms 1-10 ms 100-500 µs 5-50 µs
调度延迟抖动 高 中 低 极低
上下文切换开销 最低 低 中 较高
吞吐量影响 基准 下降约 1-3% 下降约 3-8% 下降约 5-15%
中断线程化 否 否 否 是
可睡眠锁 否 否 否 是
优先级继承 仅限 futex 仅限 futex 仅限 futex 全局支持
调优建议:对于实时测量工具链的开发,目标系统必须运行在 PREEMPT_RT 内核上。如果硬件不支持,至少应启用 PREEMPT 模型,并关闭所有动态电源管理功能(如 CPU 空闲状态、动态调频),以减少延迟不确定性。