27.临界区.md 4.5 KB

临界区

判别规则(核心,唯一要记的)

  • 数据被中断/ISR/硬件碰 → 必须临界区(关中断);只有任务碰 → 挂起调度器或互斥量
  • 临界区规则:禁止阻塞 API(会卡死)、越短越好(微秒级);多核只关本核;ISR 里要用 FromISR 版本

一句话:"临界区关中断挡一切,但挡太久实时性就完蛋。"

抽象描述(一句话本质)

临界区 = 用关中断保护的一段代码,保证执行期间不被中断/任务切换打断。是"最暴力"的互斥——连中断都挡。代价 = 中断响应延迟、调度冻结。

正反例(建立直觉)

  • 正例1taskENTER_CRITICAL(); shared_count++; taskEXIT_CRITICAL();
  • 正例2(为什么有效):单核关中断 → tick 中断进不来 → 调度器不运行 → 无任务切换、ISR 也不插入
  • 反例1:以为临界区解决所有互斥 → 多核只关本核,另一核照样访问
  • 反例2:临界区里调 vTaskDelay → 卡死(tick 被关,延时不走、没人唤醒)

ISR 是什么(补全)

ISR = Interrupt Service Routine,中断服务程序/中断处理函数。硬件事件(定时器/串口/按键/DMA)发生时 CPU 跳去执行。四特征:① 程序控制之外的上下文 → 中断里改的变量要加 volatile ② 优先级高于任何任务 ③ 不能阻塞(只能发通知)④ 要短。

易混对比

临界区 vs 挂起调度器

taskENTER_CRITICAL(关中断) vTaskSuspendAll(挂起调度器)
挡什么 中断 + 任务切换 只挡任务切换
中断响应 不能 (照常)
代价 大(中断延迟)
用于 中断也会碰的数据 只有任务碰的数据

临界区 vs 互斥量

临界区(关中断) 互斥量
挡什么 中断 + 任务 只挡任务(等待者阻塞)
适用 中断也碰的共享数据 只被任务共享
等待方式 不阻塞(硬等) 任务阻塞等锁
代价 关中断延迟中断 任务切换开销

tick 中断影响什么(补全)

tick(系统节拍,如 1ms)是 RTOS 的"心脏",驱动:① 时间片轮转(同优先级到期切换)② 延时计时(vTaskDelay/DelayUntil 到期)③ 超时检查(等信号量/队列/事件组的 timeout 到期)④ 更新 tick 计数(xTaskGetTickCount)。

所以关中断期间:tick 进不来 → 时间片不轮转、延时不计时、超时不触发 → 整个调度冻结。这就是临界区里 vTaskDelay 卡死、临界区必须短的根源。

变体验证(3 题,全过=学会)

  1. 陷阱题:临界区里调 vTaskDelay(10)卡死(tick 被关,延时永远等不到)
  2. 陷阱题:临界区持续 100ms → 中断被挡 100ms,实时性崩坏(临界区要微秒级)
  3. ISR 里能用临界区吗 → 能,但必须用 taskENTER_CRITICAL_FROM_ISR/taskEXIT_CRITICAL_FROM_ISR——普通版本在 ISR 里会错误恢复中断状态,破坏 Cortex-M 的高优先级中断嵌套

口述要点(面试怎么讲)

  • 结论先行:数据被中断碰 → 关中断(临界区);只有任务碰 → 互斥量/挂起调度器
  • 临界区 vs 互斥量:临界区关中断(挡中断+任务)、互斥量不关中断(只挡任务)——按"数据是否被中断碰"选
  • 为什么必须短:临界区一长,tick 进不来 → 时间片、延时、超时全停摆,实时性崩塌;控制在微秒级
  • FromISR 版本:普通 taskENTER_CRITICAL() 保存/恢复中断状态,在 ISR 里退出时会错误地全开中断,破坏 Cortex-M 的高优先级 ISR 嵌套;FromISR 版本保存 ISR 实际状态,正确恢复(只屏蔽同级,不破坏高优先级中断)
  • 易错点:临界区里调阻塞 API 卡死;用临界区保护纯任务数据(杀鸡用牛刀);忘了多核只关本核

关系网络

相邻概念 和本主题的关系 孤立理解会犯的错
原子操作 临界区 = 关中断实现原子性 以为临界区里能阻塞
互斥量 临界区挡中断+任务,互斥量只挡任务 拿临界区保护纯任务数据(杀鸡用牛刀)
任务状态机 关中断 → tick 不来 → 调度冻结 以为延时照常走
ISR 通信 ISR 里要用 FromISR 版本 API 在 ISR 用普通 API 破坏嵌套

学习日期

2026-08-03


每主题一页,复习时只翻本目录。