当前位置:首页>Linux>嵌入式 Linux 实时性入门:PREEMPT_RT 到底解决了什么问题?

嵌入式 Linux 实时性入门:PREEMPT_RT 到底解决了什么问题?

  • 2026-10-11 08:35:35
嵌入式 Linux 实时性入门:PREEMPT_RT 到底解决了什么问题?

关注+星标公众号,不容错过精彩

作者:HywelStar

先从一个问题说起

假设你在做一个工业机械臂控制系统,要求每 1ms 精确执行一次控制循环。你用普通的 Linux 跑了一段时间,发现大多数时候都没问题,但偶尔会出现 20ms、甚至 50ms 的"卡顿"——机械臂抖了一下。

这不是你的代码有 bug,而是普通 Linux 内核本身的设计决定了它无法满足实时。

今天这篇文章,就来聊清楚:什么是实时性、普通内核为什么做不到、PREEMPT_RT 如何解决这个问题,以及你怎么快速上手验证。

一、什么是"实时性"?

很多人第一次听到"实时",以为是"很快"。其实不对。

实时性的核心不是快,而是可预测。

一个实时系统的要求是:在规定时间内,一定能完成任务。

普通系统
实时系统
关注指标
平均响应时间
最坏响应时间(WCET)
典型场景
网页服务器
电机控制、音频采集
偶尔延迟
可以接受
不可接受

实时系统还分软实时和硬实时。工业控制、汽车 ECU 这类场景要求硬实时——错过 deadline 就是故障。

二、普通 Linux 为什么无法满足严格实时要求?

普通 Linux 的调度器设计目标是整体吞吐量最大化,不是最坏延迟最小化。主要有三个"拦路虎":

① 内核不可抢占区域

普通内核里有大量使用自旋锁(spinlock)保护的临界区。当一个低优先级任务持有自旋锁时,高优先级任务只能等着——哪怕你把任务优先级设再高也没用。这段等待时间完全不可控。

② 中断会阻塞所有任务

外设中断(比如网卡、USB)触发时,当前 CPU 会停下来执行中断服务程序(ISR)。ISR 执行期间,任何任务都被阻塞,包括你的"高优先级实时任务"。

③ 内核线程优先级混乱

普通内核里的 softirq、workqueue 等机制会在低优先级内核线程中处理大量工作,调度顺序难以精确控制。

4. 锁机制导致优先级反转

低优先级任务持有临界区锁,高优先级任务等待锁,而中等优先级任务抢占低优先级任务,导致高优先级任务被无限阻塞,这就是致命的优先级反转(Priority Inversion),标准 Linux 原生没有完善的优先级继承机制。

这四个问题加在一起,导致普通 Linux 的最坏调度延迟可能高达几十毫秒,而且无法预测。

三、PREEMPT_RT 做了什么?

PREEMPT_RT 是一组内核补丁(现在已逐步合入主线),核心思路是:让内核的几乎每一个地方都可以被高优先级任务抢占。

它主要做了三件事:

① 把自旋锁换成可睡眠的互斥锁

原本持有自旋锁时 CPU 会忙等(spin),现在换成 rt_mutex,持有锁的任务可以被挂起,让更高优先级的任务先跑。这是最关键的改动。

② 中断线程化(Threaded IRQ)

把绝大多数中断处理程序变成普通的内核线程(irqthread),这样它们就有了优先级,实时任务可以抢占中断处理线程。

③ 全面可抢占内核

通过更细粒度的锁和调度点,内核态代码的大部分路径都变得可抢占,大大缩短了高优先级任务被阻塞的时间窗口。

效果是什么?在打了 PREEMPT_RT 补丁的内核上,经过合理配置,最坏调度延迟可以控制在几十到几百微秒,而且是可预测的。

四、动手验证:用 cyclictest 测延迟

光说不练没意义,下面带你跑一个最经典的实时延迟测试工具:cyclictest。

Step 1:安装工具

# Ubuntu / Debiansudo apt install rt-tests

Step 2:跑基准测试(普通内核)

sudo cyclictest -l 100000 -m -S -p 90 -i 200 -h 400

参数说明:

  • • -l 100000:循环 10 万次
  • • -p 90:任务优先级设为 90(实时优先级)
  • • -i 200:每 200 微秒唤醒一次
  • • -h 400:统计延迟直方图

Step 3:观察输出

你会看到类似这样的输出:

T: 0 ( 1234) P:90 I:200 C:100000 Min:    8 Act:   12 Avg:   14 Max:    876

关注 Max 这一列——这是最坏延迟。普通内核上,这个数字可能飙到几百甚至上千微秒,而且每次跑结果不一样。

Step 4:换 RT 内核后对比

如果你的系统装了 PREEMPT_RT 内核(比如 Ubuntu 的 linux-image-rt-amd64),切换过去重跑同样命令,你会发现 Max 稳定很多,通常控制在 100~300 微秒以内。

五、一些常见问题

Q:我用树莓派可以跑 PREEMPT_RT 吗?

可以。树莓派有社区维护的 RT 内核镜像,搜索 raspberry pi preempt-rt 即可找到。延迟比 x86 平台高一些,但做软实时任务完全够用。

Q:打了补丁是不是系统就变慢了?

整体吞吐量会略有下降(通常 5%~15%),因为更多的上下文切换开销。嵌入式场景一般可以接受。

Q:光打补丁够吗?

不够。还需要配合:隔离 CPU(isolcpus)、关闭 CPU 节能模式、设置合适的调度策略(SCHED_FIFO),以及避免在实时线程里使用动态内存分配。这些是后续文章的内容。

小结

普通 Linux 的调度延迟不可预测,根本原因是内核中存在不可抢占的临界区和无优先级的中断机制。PREEMPT_RT 通过将自旋锁互斥化、中断线程化和全面可抢占内核三大改动,把最坏延迟压缩到可预测的微秒级。

动手的第一步很简单:装好 rt-tests,用 cyclictest 跑一跑,感受一下数字的变化。

往期推荐

STM32 擦除失败,解析Option Bytes陷阱

嵌入式里的NPU它到底能干什么?

Linux 中的 buffer 与cache

嵌入式工程师都该懂一点安全

面试技巧-2.注意要点

嵌入式中动态库路径的那些坑

嵌入式开发中常用存储认识

为什么Linux驱动会自动匹配?

设备树:每一个 Linux 驱动工程师的起点

嵌入式软件开发求职指南

A/B 分区 OTA 升级机制与 U-Boot 实现

嵌入式系统 OTA 固件升级

戳“阅读原文”一起来充电吧!

最新文章

随机文章