『7x24小时有问必答』
多核板子上任务跑在哪个核?能不能绑死?从MCU编译时绑定、FreeRTOS位图调度,到Linux的cpus_allowed位图和isolcpus隔离——不同尺度,同一套绑核思路。

一、单核并发与多核并行---本质区别

单核上的"并发"是时间片轮转制造的假象,同一微秒只有一个任务在跑。多核才是物理上的真并行——8个核可以在同一微秒各干各的。
异构多核在嵌入式里更常见:Cortex-M跑实时控制,Cortex-A跑Linux上层业务,物理分离、各跑各的固件。
理解多核协作,三个硬件概念绕不过:
Boot ROM:每个核上电后从各自入口取指令
Mailbox:核间共享寄存器,传递消息指针
IPI(核间中断):一个核向另一个核发硬件中断,通知"有事处理"
AMP和SMP不是硬件区别,而是软件组织方式——同一块SoC,跑独立镜像就是AMP,跑同一份内核调度就是SMP。
本节要点:并发是时间复用,并行是空间复用;AMP/SMP只是同一硬件上的不同软件组织。

二、MCU多核绑定---编译时隔离与运行时调度

裸机多核:编译时绑定

裸机环境下每个核烧录独立固件,链接脚本把代码钉死在对应核的Flash区域——编译时绑定,物理隔离,调度器根本不存在,也就没有"迁移"这回事。

异构AMP:一核RTOS一核裸机

典型如Cortex-M4+M0+,M4跑FreeRTOS,M0跑裸机循环。仍是编译时决定,核间通过Mailbox握手。

FreeRTOS SMP:运行时绑核

FreeRTOS 10.4+支持SMP,用位图掩码控制任务可运行的核集合:
// 绑定到Core 0和Core 2(位图:0b0101 = 0x05)

TaskHandle_t xTask = xTaskGetCurrentTaskHandle();

vTaskCoreAffinitySet(xTask,  0x05);

位图每一位对应一个核——bit0=Core0,bit1=Core1。0x05表示只允许跑在Core0和Core2。
本节要点:MCU绑核从编译时物理隔离到运行时位图掩码,粒度逐步细化。

三、Linux绑核操作---从命令行到内核位图

Linux里所有绑核手段最终收敛到task_struct.cpus_allowed位图——和FreeRTOS的位图掩码同一思路,只是层级更多。
约束类型
机制
效果
硬约束cpus_allowed
位图
任务只能跑在允许的核上,绝不越界
软约束
调度提示
建议优先选某核,但可被负载均衡覆盖
四种绑核方法:
# 1. taskset 命令行(临时绑核)

taskset -c 2,3 ./my_app               # 绑到Core2和Core3

taskset -pc 2 1234                       # 运行时改PID 1234亲和性

// 2. sched_setaffinity 系统调用

cpu_set_t  mask;

CPU_ZERO(&mask);

CPU_SET(2, &mask);

CPU_SET(3, &mask);

sched_setaffinity(0,  sizeof(mask), &mask);   // 0=当前进程

// 3. pthread_setaffinity_np 线程级(最常用)

cpu_set_t  mask;

CPU_ZERO(&mask);

CPU_SET(2, &mask);

pthread_setaffinity_np(pthread_self(),  sizeof(mask), &mask);

# 4. cgroup cpuset 容器级

mkdir  /sys/fs/cgroup/cpuset/rt_group

echo  "2-3"  > /sys/fs/cgroup/cpuset/rt_group/cpus

echo  "1234"  > /sys/fs/cgroup/cpuset/rt_group/tasks

select_task_rq是调度器选核的核心:遍历cpus_allowed位图,在允许的核中找负载最低的。位图置0的核,调度器连看都不会看。

isolcpus内核隔离

启动参数isolcpus=2,3把Core2和Core3从调度器的负载均衡中摘出——普通任务不会被调度过去,只有手动绑核的任务才能跑上去,适合硬实时场景:
# 完整实时隔离配置(内核启动参数)

isolcpus=2,3 nohz_full=2,3 rcu_nocbs=2,3 irqaffinity=0,1

本节要点:所有绑核API最终写入同一个位图;isolcpus让隔离核彻底脱离调度器管辖。

四、核间通信与启动IPI机制对比

核间通信是多核协作的骨架。MCU和Linux的IPI机制本质相同,封装层级不同。
IPI类型
MCU实现
Linux实现
用途
请求调度
SGI中断
resched_cpu()
通知对核重新调度
函数调用
Mailbox
smp_call_function_single()
在指定核执行函数
软中断
SGI+Mailbox
raise_softirq()
延迟处理核间任务
停机
WFI
smp_send_stop()
系统关机时停核

启动机制对比

阶段
MCU AMP
Linux SMP
上电
各核独立从Boot ROM启动
BSP核启动,通过PSCI唤醒从核
初始化
各核独立初始化外设
BSP核初始化全局资源,从核等唤醒
调度
各核独立调度器
统一调度器,全局负载均衡
本节要点:IPI是多核协作的硬件基础,MCU和Linux只是封装层级不同。

五、注意事项

坑
现象
解法
绑死单核不设亲和性掩码
任务被负载均衡迁走,时序抖动
sched_setaffinity
或isolcpus双保险
isolcpus
不隔离中断
网卡中断打到隔离核,实时任务被抢占
irqaffinity
配合设置中断亲和性
线程绑核但进程没绑
新线程继承进程亲和性,覆盖线程设置
进程和线程同时设亲和性
cgroup cpuset未设mems
NUMA节点跨核访存,延迟飙升
同时设置cpuset.mems绑定内存节点
FreeRTOS SMP位图写错
0x03
本想绑Core0和Core3,实际绑Core0和Core1
确认位图:bit N = Core N
nohz_full
不配rcu_nocbs
RCU回调在隔离核执行,破坏实时性
nohz_full
和rcu_nocbs必须成对配置
本节要点:绑核不是设个掩码就完事,中断、RCU、NUMA、继承关系都要同步处理。

六、总结

绑核本质是给调度器画圈——告诉它"这个任务只能在这些核上跑"
MCU从编译时绑定到FreeRTOS SMP运行时位图,同一条路的粗细粒度之别
Linux四种绑核API殊途同归,都写进task_struct.cpus_allowed位图
isolcpus+nohz_full+rcu_nocbs+irqaffinity是硬实时隔离的标准组合
从MCU的链接脚本到Linux的cpus_allowed位图,绑核这件事——不同尺度,同一个圈。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

上一主题上一主题         下一主题下一主题
QQ手机版小黑屋粤ICP备17165530号

关于我们·投诉举报· 用户帮助· 联系我们 · 本站服务 · 版权声明· 隐私政策 · 投搞指南

法律保护:PLC技术网,plcjs.com,plcjs.net等字样
Copyright 2010-2030. All rights reserved. 


微信公众号二维码 抖音二维码 百家号二维码 今日头条二维码哔哩哔哩二维码