news 2026/4/23 0:10:21

Linux RT 调度器的 rq_online/offline:CPU 上下线时的 RT 任务处理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux RT 调度器的 rq_online/offline:CPU 上下线时的 RT 任务处理

一、核心概念

1. RT 调度基础

  • SCHED_FIFO/SCHED_RR:Linux 标准实时调度策略,优先级 1–99,数值越高优先级越高,可抢占普通 CFS 任务。
  • rt_rq:每个 CPU 运行队列 rq 内嵌的实时队列,按优先级位图管理就绪任务,是 RT 调度的核心数据结构。
  • pushable_tasks:CPU 上可被迁移的 RT 任务链表,用于过载与 CPU 下线场景的任务推送。
  • root_domain:多核系统中 RT 任务可迁移的 CPU 集合,决定任务迁移范围。

2. CPU 热插拔与调度回调

  • CPUHP_AP_ONLINE:CPU 上线完成后触发,调度器执行 rq_online 初始化 RT 队列。
  • CPUHP_AP_OFFLINE:CPU 下线前触发,调度器执行 rq_offline 迁移所有 RT 任务。
  • rq_online():启用当前 CPU 的 RT 运行队列,刷新优先级位图,加入根域均衡拓扑。
  • rq_offline():排空当前 CPU 所有 RT 任务,推送至其他在线 CPU,关闭本地 RT 队列。

3. RT 任务迁移机制

  • push_rt_tasks:CPU 主动将可迁移 RT 任务推送到其他轻载 CPU。
  • pull_rt_task:空闲 CPU 主动拉取高优先级 RT 任务,保障低延迟调度。
  • 迁移安全点:任务必须处于可调度状态,禁止迁移正在运行的 RT 任务,避免死锁与数据不一致。

二、环境准备

硬件环境

  • x86_64 多核服务器(≥4 核),支持 CPU 热插拔;嵌入式 ARM64 平台亦可。

软件环境

  • 操作系统:CentOS Stream 9 / Ubuntu 22.04
  • 内核版本:Linux 5.15 LTS(开启 CONFIG_CPU_HOTPLUG、CONFIG_RT_GROUP_SCHED、CONFIG_SCHED_DEBUG)
  • 开发工具:gcc、gdb、trace-cmd、kernel-debuginfo、chrt、taskset

环境配置步骤

  1. 安装依赖
yum install -y gcc gdb trace-cmd kernel-debuginfo taskset util-linux
  1. 检查内核配置
zcat /proc/config.gz | grep -E "CPU_HOTPLUG|RT_GROUP_SCHED|SCHED_DEBUG"
  1. 临时启用 CPU 热插拔(非物理热插拔)
# 下线CPU1 echo 0 > /sys/devices/system/cpu/cpu1/online # 上线CPU1 echo 1 > /sys/devices/system/cpu/cpu1/online
  1. 开启调度调试
echo 1 > /sys/kernel/debug/sched_features mount -t debugfs none /sys/kernel/debug

三、典型应用场景

在 5G 小基站 DU 单元中,设备会根据业务负载动态关闭空闲 CPU 以降低功耗。基带处理与空口调度为优先级 80 的 SCHED_FIFO RT 任务,当 CPU1 被系统下线时,RT 调度器必须在毫秒级将该 CPU 上的 RT 任务迁移至 CPU0/2/3,若迁移失败会导致空口失步引发终端掉线。在车载域控制器中,MCU 故障触发 CPU 离线时,自动驾驶感知 RT 任务需无缝迁移至备用 CPU,保证制动与转向控制不中断。CPU 上线时,调度器快速重建 rt_rq,接纳迁移回流的 RT 任务,恢复系统吞吐与实时性。该机制同样用于边缘计算节点的故障自愈与工业 PLC 的冗余切换,是实时 Linux 系统高可用的关键保障。


四、内核源码与实战案例

1. 核心源码路径

kernel/sched/core.c # rq_online/rq_offline 入口 kernel/sched/rt.c # RT任务迁移、push/pull实现 include/linux/sched/rt.h # RT队列结构体定义

2. rq_offline 流程(CPU 下线)

// kernel/sched/core.c void rq_offline(struct rq *rq) { raw_spin_lock_irq(&rq->lock); // 标记队列离线,禁止新任务入队 rq->online = false; // 排空RT任务,强制迁移所有可推送任务 push_rt_tasks(rq); // 清空本地RT优先级位图 bitmap_zero(rq->rt.rt_prio.bitmap, MAX_RT_PRIO); rq->rt.highest_prio.curr = MAX_RT_PRIO; rq->rt.highest_prio.next = MAX_RT_PRIO; raw_spin_unlock_irq(&rq->lock); }

作用:CPU 下线前锁定队列,推送全部 RT 任务,清空优先级状态,避免离线 CPU 残留任务导致调度死锁。

3. rq_online 流程(CPU 上线)

// kernel/sched/core.c void rq_online(struct rq *rq) { raw_spin_lock_irq(&rq->lock); // 标记队列在线 rq->online = true; // 重置RT队列状态 rq->rt.rt_nr_running = 0; bitmap_zero(rq->rt.rt_prio.bitmap, MAX_RT_PRIO); rq->rt.highest_prio.curr = MAX_RT_PRIO; rq->rt.highest_prio.next = MAX_RT_PRIO; // 将CPU加入根域,允许任务pull/push rq->rd = cpu_rq(smp_processor_id())->rd; raw_spin_unlock_irq(&rq->lock); // 触发全局均衡,拉取高优RT任务 schedule_run_next(); }

作用:初始化 RT 队列,加入负载均衡拓扑,触发任务拉取,快速承接 RT 负载。

4. RT 任务推送核心实现

// kernel/sched/rt.c static int push_rt_tasks(struct rq *rq) { struct task_struct *p, *n; int pushed = 0; list_for_each_entry_safe(p, n, &rq->rt.pushable_tasks, pushable_tasks) { struct rq *target_rq; // 选择同根域内最优目标CPU target_rq = pick_optimal_rt_cpu(rq, p); if (!target_rq) continue; // 迁移任务至目标CPU if (migrate_task(rq, p, target_rq) == 0) pushed++; } return pushed; }

作用:遍历可迁移 RT 任务,按优先级与负载选择目标 CPU,完成原子迁移。

5. 用户态 RT 任务测试程序

#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <sched.h> #include <unistd.h> #include <sys/types.h> #define RT_PRIO 80 #define CPU_ID 1 void *rt_thread_func(void *arg) { cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(CPU_ID, &cpuset); // 绑定CPU1 if (pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset) != 0) perror("pthread_setaffinity_np failed"); while (1) { // 空循环占用CPU usleep(1000); } return NULL; } int main() { pthread_t tid; struct sched_param param; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setschedpolicy(&attr, SCHED_FIFO); param.sched_priority = RT_PRIO; pthread_attr_setschedparam(&attr, &param); pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); if (pthread_create(&tid, &attr, rt_thread_func, NULL) != 0) { perror("pthread_create failed"); return -1; } pthread_join(tid, NULL); return 0; }

编译运行

gcc rt_test.c -o rt_test -lpthread -rt chrt -f 80 ./rt_test

6. 调试命令实战

  1. 查看 RT 任务绑定 CPU
ps -eo pid,pri,cmd,psr | grep -E "rt_test|chrt"
  1. 下线 CPU 并观察迁移
echo 0 > /sys/devices/system/cpu/cpu1/online ps -eo pid,pri,cmd,psr | grep rt_test
  1. 跟踪调度事件
trace-cmd record -e sched:sched_switch -e sched:sched_migrate_task trace-cmd report
  1. 查看 RT 队列状态
cat /sys/kernel/debug/sched/rt_rq/cpu1

五、常见问题与解答

Q1:CPU 下线后 RT 任务未迁移,导致任务卡住

原因:任务被 CPU 亲和性严格绑定(nr_cpus_allowed=1),无可用迁移目标。解决方案:放宽 cpuset 允许跨 CPU 迁移,或在离线前主动重设亲和性。

taskset -cp 0-3 <pid>

Q2:rq_offline 触发死锁,系统卡死

原因:迁移时持有 rq 锁重入,或任务处于 RUNNING 状态被强制迁移。解决方案:升级内核至 5.15+,关闭 PREEMPT_RT 与热插拔混用,迁移前确保任务可调度。

Q3:CPU 上线后 RT 任务不回流,负载不均

原因:root_domain 未更新,均衡未触发。解决方案:手动触发均衡

echo 1 > /proc/sys/kernel/sched_rt_period_us

Q4:RT 任务迁移后调度延迟飙升

原因:缓存失效、目标 CPU 过载、优先级反转。解决方案:使用 SCHED_DEADLINE 替代,绑定 LLC 节点,避免跨 NUMA 迁移。


六、实践建议与最佳实践

  1. RT 任务亲和性配置线上 RT 任务禁止绑定单一 CPU,应设置为同 NUMA 节点内多 CPU,提升热插拔容错。
CPU_SET(0, &cpuset); CPU_SET(1, &cpuset); CPU_SET(2, &cpuset);
  1. 热插拔顺序优化下线 CPU 前先降低其负载,避免瞬时大规模迁移;上线后立即触发 pull_rt_task,快速承接高优任务。

  2. 优先级保护关键 RT 任务优先级≥80,避免被非关键任务抢占;禁用普通任务提升优先级至 RT 范围。

  3. 内核参数调优

sysctl -w kernel.sched_rt_runtime_us=950000 sysctl -w kernel.sched_rt_period_us=1000000

限制 RT 任务总占用,防止系统饿死。

  1. 监控告警持续监控 rt_rq.nr_running、迁移次数、CPU 在线状态,异常时自动触发冗余切换。

七、总结

rq_online 与 rq_offline 是 RT 调度器适配 CPU 热插拔的基石,通过队列状态管理、RT 任务原子推送 / 拉取、优先级位图刷新与根域重均衡,保证 CPU 上下线过程中 RT 任务不丢失、不卡死、调度延迟可控。在实时系统中,CPU 热插拔不再是单纯的节能手段,而是高可用自愈的核心能力。

本文提供的源码分析、测试程序与调试命令可直接用于论文实验、项目验证与线上故障定位。建议开发者结合 trace-cmd 与内核调试深入理解迁移细节,在工业控制、车载、5G 等场景中落地时,务必做长时间压力测试,确保极端场景下实时性与稳定性达标。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 0:06:16

如何在5分钟内实现单机游戏本地多人:Nucleus Co-Op完整指南

如何在5分钟内实现单机游戏本地多人&#xff1a;Nucleus Co-Op完整指南 【免费下载链接】nucleuscoop Starts multiple instances of a game for split-screen multiplayer gaming! 项目地址: https://gitcode.com/gh_mirrors/nu/nucleuscoop 还在为单机游戏无法与朋友共…

作者头像 李华
网站建设 2026/4/23 0:02:02

从ADRV9002到ADRV9003:手把手教你移植FPGA驱动,避开那些官方没说的坑

从ADRV9002到ADRV9003&#xff1a;FPGA驱动移植实战指南与避坑手册 当硬件工程师第一次拿到ADRV9003评估板时&#xff0c;往往会发现一个令人头疼的事实——ADI官方并没有提供现成的FPGA驱动。这与ADRV9002完善的驱动支持形成鲜明对比。作为ADI新一代射频收发器&#xff0c;ADR…

作者头像 李华
网站建设 2026/4/22 23:56:17

micronet错误排查手册:常见问题与解决方案大全

micronet错误排查手册&#xff1a;常见问题与解决方案大全 【免费下载链接】micronet 项目地址: https://gitcode.com/gh_mirrors/mic/micronet micronet是一个专注于模型压缩与部署的深度学习工具包&#xff0c;提供了剪枝、量化和TensorRT部署等核心功能。本手册将帮…

作者头像 李华
网站建设 2026/4/22 23:51:25

CSS如何制作标签页效果_利用display flex与盒模型

Flex布局标签页头部最可控&#xff0c;需设flex容器、防换行、处理min-width&#xff1b;切换内容用visibility:hidden更优&#xff1b;必同步aria-selected和role属性&#xff1b;移动端优先用scroll-snap实现滑动。用 display: flex 布局标签页头部&#xff0c;别碰 float 或…

作者头像 李华