必须打PREEMPT_RT补丁、中断线程化并CPU绑定、实时核隔离与内存锁定、设置实时策略及RT带宽防护,四层闭环缺一不可,否则无法将调度延迟稳定压至微秒级。

要让 Linux 内核真正支持硬实时抢占、把调度延迟压到微秒级,不能只靠 make menuconfig 里勾个选项。必须做四层闭环改造:内核补丁、中断处理、CPU 调度、运行时保护。缺一不可。
必须打 PREEMPT_RT 补丁
主线内核默认不带实时抢占能力。哪怕你选了 CONFIG_PREEMPT=y,自旋锁保护的临界区依然不可抢占,中断还是硬上下文、优先级最高且不可打断。真正的低延迟起点是官方 RT 补丁。
- 下载与内核版本严格匹配的 patch,比如用 5.15.0 就只能用
patch-5.15-rt59.patch.xz - 解压源码后,用
xzcat ../xxx.patch.xz | patch -p1打入,失败说明版本不匹配 - 配置时启用
CONFIG_PREEMPT_RT=y,同时确保CONFIG_HIGH_RES_TIMERS=y、CONFIG_TIMERFD=y
中断必须线程化并绑定 CPU
硬件中断(IRQ)是抖动最大来源。标准内核中 IRQ 一触发就停掉所有调度,哪怕只花 300μs,也足以让 125μs 的 EtherCAT 周期超时。
- PREEMPT_RT 已将大部分中断转为可调度线程(如
irq/47: eth0),但还需手动隔离 - 查看当前中断分布:
cat /proc/interrupts - 把网卡、USB、声卡等非实时外设的 IRQ 绑定到非实时 CPU(比如 CPU1):
echo 2 > /proc/irq/47/smp_affinity_list # 把 irq 47 固定到 CPU2
- 开机自动绑定需写入
/etc/default/grub添加irqaffinity=2-3(假设 CPU0/CPU1 专用于实时任务)
实时任务要独占 CPU 并锁定内存
多核调度默认均衡负载,进程在不同核心间迁移会清空 L1/L2 缓存,单次代价可达 500μs。
- 启动内核时加参数
isolcpus=0,1 nohz_full=0,1 rcu_nocbs=0,1,隔离出专用实时核 - 用
taskset -c 0 ./my_realtime_app强制程序只跑在 CPU0 - 程序启动前锁定全部内存页:
mlockall(MCL_CURRENT | MCL_FUTURE),避免缺页中断打断
运行时必须设实时策略 + 带宽防护
光有内核和绑核还不够。普通进程仍可能意外抢占,而 bug 导致的实时任务死循环会直接锁死系统。
- 用
chrt -f 80 ./my_app启动 FIFO 实时任务,优先级 80(1–99 可用) - 设置 RT 带宽限制,防止单个任务吃光 CPU:
echo 950000 > /proc/sys/kernel/sched_rt_runtime_us # 每秒最多用 950ms echo 1000000 > /proc/sys/kernel/sched_rt_period_us # 周期 1 秒
- 若用
SCHED_DEADLINE,需指定周期、运行时间和截止时间,单位均为纳秒
这些步骤环环相扣。只做其中一两项,cyclictest 测试很可能仍出现几百微秒的尖峰。实际工业部署中,往往还要配合 trace-cmd 抓取 sched_switch 和 irq_handler_entry 事件,定位具体哪段代码或哪个中断导致了延迟。


















