Linux 不是硬实时 OS,但通过 SCHED_FIFO/RR + PREEMPT_RT 补丁(6.12 主线合入),它在音视频、工业、机器人、金融交易等场景里占据了一席之地。本文讲”把 Linux 变实时”的三层:policy、抢占模型、RT 补丁。
一、先看图:三层抢占模型
flowchart TB
subgraph PreemptNone[PREEMPT_NONE]
N1[内核态全部不可抢占]
N2[延迟可达 100+ms]
end
subgraph PreemptVoluntary[PREEMPT_VOLUNTARY]
V1[cond_resched 点可抢]
V2[延迟 10-50ms]
end
subgraph PreemptNormal[PREEMPT]
P1[大部分内核可抢]
P2[延迟 1-5ms]
end
subgraph PreemptRT[PREEMPT_RT]
R1[几乎全可抢]
R2[spinlock → rt_mutex]
R3[IRQ → threaded]
R4[延迟 μs 级]
end
PreemptNone --> PreemptVoluntary --> PreemptNormal --> PreemptRT
classDef low fill:#f8514922,stroke:#f85149,color:#adbac7;
classDef mid fill:#f0883e22,stroke:#f0883e,color:#adbac7;
classDef hi fill:#3fb95022,stroke:#3fb950,color:#adbac7;
class N1,N2 low
class V1,V2 mid
class P1,P2,R1,R2,R3,R4 hi
二、实时调度 policy
2.1 SCHED_FIFO
- 固定优先级 1-99(越大越高)
- 同级按 FIFO:跑到自愿让出或被更高级抢
- 不 auto-yield,没有时间片
典型:chrt -f 50 ./worker
危险:一个 while(1) 的 FIFO
任务会永占 CPU,把同级以下全饿。必须有
RT-throttling(见第 5 节)或 watchdog。
2.2 SCHED_RR
- 同 FIFO 但同级内 round-robin
- 时间片
sched_rr_timeslice_ms(默认 100ms)
SCHED_RR 比 FIFO 略安全(至少同级间会让),但对跨级仍有独占问题。
2.3 优先级层次
SCHED_DEADLINE (最先)
SCHED_FIFO/RR prio 99..1
SCHED_NORMAL (EEVDF)
SCHED_BATCH
SCHED_IDLE
DEADLINE 高于所有 RT;RT 高于 NORMAL。
2.4 RLIMIT_RTPRIO、RLIMIT_RTTIME
普通用户默认不能用 SCHED_FIFO。需要
CAP_SYS_NICE 或调 ulimit -r +
/etc/security/limits.conf。
RLIMIT_RTTIME 限 RT
任务连续运行时间(μs),超限降级成 SCHED_OTHER 或收
SIGXCPU。防失控。
三、cyclictest:RT 基线
测量”从 hrtimer 到用户态被唤醒”的实际延迟。
cyclictest -p 80 -t 4 -D 1h -i 200 -m输出 min/avg/max 延迟(μs)。
典型结果:
| 系统 | avg | max |
|---|---|---|
| 通用服务器 PREEMPT | 15 μs | 300+ μs |
| PREEMPT + isolcpus + nohz_full | 5 μs | 50 μs |
| PREEMPT_RT 调优 | 3 μs | 20 μs |
| 高端嵌入式 + PREEMPT_RT | 2 μs | 10 μs |
max 是关键——硬实时看 worst case,不是平均。
四、PREEMPT_RT:补丁集 20 年历史
2004 Ingo Molnár 起的补丁集,目标:把内核抢占点减到最少。改造点:
- spinlock →
rt_mutex(大部分):
spinlock_t能睡 + 继承优先级 - raw_spinlock_t:真正的自旋,少数必须不能睡的场景
- IRQ handler
线程化:
IRQF_NO_THREAD外默认跑在内核线程里,可抢 - softirq
线程化:
ksoftirqd/N运行 softirq;RT 任务可抢它 - printk 异步化:不在 IRQ 上下文同步写 console
2023 年开始逐步合入主线;6.12(2024 Q4)宣告 “upstream merge 完成”。
4.1 代价
- 吞吐下降 5-20%:rt_mutex 比 spinlock 重
- 代码复杂:新增非常多抽象层
- 必须关
CONFIG_PREEMPT_RT来测试——编译选项一整套改变
建议:只对有硬实时需求的系统开 PREEMPT_RT。通用服务器不需要。
4.2 rt_mutex 与优先级继承
经典优先级反转场景:L 持锁 → H 等锁 → M 抢 CPU → L 跑不了 → H 更等不到。
rt_mutex 的 PI:H 等锁时,L 临时升到 H 的优先级直到释放。Linux 中断链接起来,PI 可级联。
PI
在用户态也有:PTHREAD_PRIO_INHERIT。futex2 /
FUTEX_PI 是内核支持。
五、RT-throttling:防失控 FIFO
内核默认
/proc/sys/kernel/sched_rt_period_us = 1000000(1
s)和 sched_rt_runtime_us = 950000(0.95
s)——每秒 RT 任务最多跑 0.95 秒,剩余 0.05 秒给
SCHED_OTHER。
防 while(1) FIFO 锁死系统;但在严肃 RT
系统里常把 runtime 设 -1(无限制),因为你自己得保证 RT
任务短。
六、RT 系统调优清单
- Isolate
CPU:
isolcpus=2,3 nohz_full=2,3 rcu_nocbs=2,3,让某些核不跑 housekeeping - 禁用 SMT:减少 cache 抖
- 绑 IRQ:把无关 IRQ 绑到 housekeeping CPU
- 禁用 C-states
深度:
intel_idle.max_cstate=1——换延迟换能耗 - 关 TurboBoost / P-state:频率稳定
- 内存预分配 / mlockall:避免 page fault 延迟
- huge page:减 TLB miss
- PREEMPT_RT 内核:如果 max 要求 < 50μs
这些在工业 PLC、机器人控制、专业音频(JACK)、HFT 交易系统里都是标配。
七、用户态配合
struct sched_param sp = { .sched_priority = 80 };
sched_setscheduler(0, SCHED_FIFO, &sp);
mlockall(MCL_CURRENT | MCL_FUTURE); // 防被换出- mlockall 防 swap/lazy-alloc 延迟
- 预热缓存:跑一次 hot path 让 TLB / I-cache 热
- 避免分配器大页(glibc malloc 有不可抢占段)
八、常见 RT bug
bug A:FIFO 任务永 spin,整台机死 原因:没 RT-throttling 或 RTTIME 解决:throttling 配置、应用代码加主动 yield
bug B:cyclictest max spike 1ms+
原因:SMI(System Management
Interrupt)、NMI、CPU 频率切换
诊断:hwlatdetect 工具
bug C:PREEMPT_RT 编译后网络驱动不稳 原因:某些驱动假设 spinlock 不睡,被 rt_mutex 改后触发 bug 解决:换更新的驱动;这是 RT 在上游完整合入前长期痛点
bug D:优先级反转仍现 原因:锁不是 rt_mutex(某些用户态 lock 没 PI) 解决:pthread mutex + PTHREAD_PRIO_INHERIT
九、小结
- SCHED_FIFO/RR 提供 99 级静态优先级;FIFO 永跑、RR 轮转
- RT-throttling、RLIMIT_RTTIME 防失控
- PREEMPT_RT 20 年磨一剑,6.12 合入主线;通用场景不用
- cyclictest + hwlatdetect + 系统调优构成 RT 基线
- 硬实时要 rt_mutex + 优先级继承
下一篇 C-23 讲 SCHED_DEADLINE——EDF+CBS 在内核的落地,以及为什么它是”保量调度”的正确姿势。
参考文献
- Gleixner, T. “The real-time patch set.” LWN.net 2004-2024(系列)
- Corbet, J. “The realtime preemption patch.” LWN.net 2020-2024
Documentation/scheduler/sched-rt-group.rst- Liu & Layland 1973;Sha et al. “Priority inheritance protocols” IEEE Trans. Computers 1990
- Arnd Bergmann et al. “Real-time Linux landing.” ELC 2024 talks
rt-tests套件:cyclictest、hackbench、hwlatdetect
工具
cyclictest—— RT 基线hwlatdetect—— 硬件延迟rt-tests套件chrt -f/-r -p <pid>—— 查/设置 policytuned-adm profile realtime—— 一键调优
上一篇:EEVDF 下一篇:SCHED_DEADLINE:EDF+CBS 的落地
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【操作系统百科】优先级反转与继承
火星探路者号因优先级反转重启——这是实时系统最经典的故事。本文讲优先级反转现象、PIP 优先级继承协议、PCP 优先级天花板、rt_mutex、PREEMPT_RT 的 spinlock 转换、DEADLINE 任务反转。
【操作系统百科】实时 OS 巡礼
VxWorks/QNX/Zephyr 与 Linux PREEMPT_RT 的工程取舍——硬实时 vs 软实时、静态调度、ARINC-653 分区、安全认证(DO-178C)、最小内存占用。
【操作系统百科】线程化中断
把 IRQ handler 线程化——PREEMPT_RT 的核心改造之一。本文讲 request_threaded_irq、handler/thread_fn 分工、IRQF_ONESHOT、全线程化的延迟与吞吐代价、softirq 线程化趋势。
【操作系统百科】futex
glibc pthread_mutex 背后是 futex——用户态快路径无 syscall,竞争时才进内核。本文讲 FUTEX_WAIT/WAKE、PI futex、robust futex、futex2、requeue、安全补丁与工程陷阱。