2. 嵌入式并发基础

在嵌入式系统里谈“并发”,并不是单纯追求同时做很多事,而是要在有限的 CPU 主频、内存和功耗预算下,让多个外部事件与内部逻辑都能被及时、可预测地处理。理解并发与并行的区别,以及任务、线程、进程、中断、实时性这些术语在嵌入式语境中的真实含义,是后续设计任务架构和选择同步机制的基础。

一、并发与并行:逻辑同时与物理同时

并发(Concurrency)强调的是“多个执行流在逻辑上同时存在并推进”。在单核 MCU 上,通常通过时间片轮转、协作式调度或中断抢占,让多个任务交替使用 CPU。任一时刻只有一个任务真正占用内核,但宏观上它们都在向前推进。并行(Parallelism)则强调“同一时刻多个执行流真正同时执行”,必须有多核、多核异构(如 Cortex-A + Cortex-M)、DMA 通道或硬件外设等物理资源支撑。

可以用一个直观判断:单核 RTOS 上跑三个任务,是并发;双核 MCU 上两个任务分别跑在两个核上,是并行;DMA 搬运串口数据的同时 CPU 在计算 PID,也是并行。嵌入式里大量场景其实是“并发 + 局部并行”,例如 CPU 处理协议栈,DMA 负责 ADC 采样,定时器硬件负责精确计时。

并发是“结构”问题,解决的是如何组织多个执行流;并行是“资源”问题,解决的是如何让它们真正同时跑。设计时先想清楚哪些必须并行,哪些只需并发即可。

二、任务、线程、进程:抽象层级不同

在嵌入式 RTOS(FreeRTOS、RT-Thread、Zephyr 等)中,任务(Task)是最基本的调度单位,通常拥有独立的栈空间和优先级,由内核统一调度。任务之间共享同一地址空间,切换开销小,适合资源受限的 MCU。

线程(Thread)在通用操作系统(Linux、QNX、VxWorks)中是与进程并列的调度单位,同一进程内的多个线程共享代码段、数据段和文件描述符,但各自拥有栈和寄存器上下文。嵌入式 Linux 中常用 pthread 创建线程,适合功能较复杂、需要文件系统和网络协议栈的场景。

进程(Process)拥有独立的虚拟地址空间和资源,隔离性强但创建和切换开销大。嵌入式 Linux 中常用进程做功能隔离,例如一个进程负责采集,一个进程负责通信,通过共享内存或消息队列交互。MCU 上一般没有 MMU,很少使用真正的进程概念,更多是“任务”或“裸机前后台”。

概念地址空间切换开销典型载体嵌入式适用场景
任务 Task共享很小FreeRTOS / RT-ThreadMCU 实时控制、周期采样
线程 Thread共享中等Linux pthread / QNX嵌入式 Linux 多业务并行
进程 Process独立较大Linux / VxWorks功能隔离、故障隔离
中断 ISR共享极小所有 MCU / SoC紧急事件、硬件响应

三、中断:嵌入式并发的“硬入口”

中断是嵌入式系统区别于通用计算的重要特征。它由硬件触发,打断当前执行流,跳转到中断服务程序(ISR)执行。中断的优先级通常高于任何任务,因此 ISR 必须短小、快速、无阻塞。常见做法是“上半部”在 ISR 中只做最紧急的处理(清标志、读寄存器、发信号量),把耗时逻辑放到“下半部”的任务中完成。

void EXTI0_IRQHandler(void) {
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    if (EXTI_GetITStatus(EXTI_Line0) != RESET) {
        EXTI_ClearITPendingBit(EXTI_Line0);
        // 上半部:只发通知,不处理业务
        vTaskNotifyGiveFromISR(xSensorTask, &xHigherPriorityTaskWoken);
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
}

中断与任务的关系可以理解为:中断负责“事件到达”,任务负责“事件处理”。如果 ISR 里做浮点运算、打印日志或等待信号量,就会导致系统实时性急剧下降,甚至丢中断。

四、实时性:确定性比速度更重要

实时性(Real-time)不是“跑得快”,而是“在确定的时间约束内完成响应”。硬实时要求绝对不能错过截止时间,例如电机换相、安全气囊触发;软实时允许偶尔超时,例如界面刷新、日志上传。嵌入式实时系统关注的是最坏情况执行时间(WCET)、中断延迟、任务切换时间和优先级反转。

常见实时性指标包括:中断延迟(从中断触发到 ISR 第一条指令)、调度延迟(从任务就绪到真正运行)、抖动(周期任务实际周期与理想周期的偏差)。在 Cortex-M 上,中断延迟通常为十几个时钟周期;在 Linux 上,普通内核可能达到毫秒级,需要 PREEMPT_RT 补丁才能进入几十微秒级。

不要用“平均响应时间”评估实时性。实时系统看的是最坏情况。一个平均 10μs、偶尔 10ms 的路径,对硬实时来说就是不可接受的。

五、嵌入式场景特点与典型误区

嵌入式并发与通用服务器并发有显著差异:资源极度受限(KB 级 RAM、无 MMU)、事件来源以中断和 DMA 为主、对功耗和确定性要求高、常常需要裸机与 RTOS 混合。因此,任务数量不宜过多,优先级设计要精简,同步机制优先选择信号量、消息队列、事件标志组,而不是重量级锁。

常见误区包括:把并发当并行,以为单核上多任务就是同时执行;在 ISR 中调用阻塞 API;任务优先级设置随意导致优先级反转;用全局变量在任务和中断之间传递数据却不加保护;以及忽视栈溢出,任务栈给得过小。复盘时可以用“事件—响应—截止时间”三列表格逐条检查每个并发路径,确认最坏情况是否满足要求。

嵌入式并发核心概念关系 硬件事件 GPIO / 定时器 / ADC DMA 通道 无 CPU 搬运数据 通信外设 UART / SPI / CAN 中断 ISR(上半部) 清标志 · 读寄存器 · 发通知 · 必须短小 RTOS 调度器 优先级抢占 · 时间片 · 任务切换 高优先级任务 电机控制 / 安全响应 中优先级任务 协议解析 / 数据处理 低优先级任务 日志 / 界面 / 状态上报 通知 / 唤醒 并行路径 DMA 搬运与 CPU 计算同时进行 实时性约束 中断延迟 · 调度延迟 · 抖动

把这张关系图记在脑子里:硬件事件和 DMA 是并发的物理来源,中断是硬入口,RTOS 调度器是并发的中枢,任务是并发的执行体,而实时性约束贯穿整条链路。后续设计任务架构时,先问三个问题——哪些事件必须并行、哪些只需并发、最坏响应时间是多少——答案会直接决定你选择任务、线程还是中断下半部。