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-Thread | MCU 实时控制、周期采样 |
| 线程 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 补丁才能进入几十微秒级。
五、嵌入式场景特点与典型误区
嵌入式并发与通用服务器并发有显著差异:资源极度受限(KB 级 RAM、无 MMU)、事件来源以中断和 DMA 为主、对功耗和确定性要求高、常常需要裸机与 RTOS 混合。因此,任务数量不宜过多,优先级设计要精简,同步机制优先选择信号量、消息队列、事件标志组,而不是重量级锁。
常见误区包括:把并发当并行,以为单核上多任务就是同时执行;在 ISR 中调用阻塞 API;任务优先级设置随意导致优先级反转;用全局变量在任务和中断之间传递数据却不加保护;以及忽视栈溢出,任务栈给得过小。复盘时可以用“事件—响应—截止时间”三列表格逐条检查每个并发路径,确认最坏情况是否满足要求。
把这张关系图记在脑子里:硬件事件和 DMA 是并发的物理来源,中断是硬入口,RTOS 调度器是并发的中枢,任务是并发的执行体,而实时性约束贯穿整条链路。后续设计任务架构时,先问三个问题——哪些事件必须并行、哪些只需并发、最坏响应时间是多少——答案会直接决定你选择任务、线程还是中断下半部。