一句话:"临界区关中断挡一切,但挡太久实时性就完蛋。"
临界区 = 用关中断保护的一段代码,保证执行期间不被中断/任务切换打断。是"最暴力"的互斥——连中断都挡。代价 = 中断响应延迟、调度冻结。
taskENTER_CRITICAL(); shared_count++; taskEXIT_CRITICAL();vTaskDelay → 卡死(tick 被关,延时不走、没人唤醒)ISR = Interrupt Service Routine,中断服务程序/中断处理函数。硬件事件(定时器/串口/按键/DMA)发生时 CPU 跳去执行。四特征:① 程序控制之外的上下文 → 中断里改的变量要加 volatile ② 优先级高于任何任务 ③ 不能阻塞(只能发通知)④ 要短。
临界区 vs 挂起调度器:
taskENTER_CRITICAL(关中断) |
vTaskSuspendAll(挂起调度器) |
|
|---|---|---|
| 挡什么 | 中断 + 任务切换 | 只挡任务切换 |
| 中断响应 | 不能 | 能(照常) |
| 代价 | 大(中断延迟) | 小 |
| 用于 | 中断也会碰的数据 | 只有任务碰的数据 |
临界区 vs 互斥量:
| 临界区(关中断) | 互斥量 | |
|---|---|---|
| 挡什么 | 中断 + 任务 | 只挡任务(等待者阻塞) |
| 适用 | 中断也碰的共享数据 | 只被任务共享 |
| 等待方式 | 不阻塞(硬等) | 任务阻塞等锁 |
| 代价 | 关中断延迟中断 | 任务切换开销 |
tick(系统节拍,如 1ms)是 RTOS 的"心脏",驱动:① 时间片轮转(同优先级到期切换)② 延时计时(vTaskDelay/DelayUntil 到期)③ 超时检查(等信号量/队列/事件组的 timeout 到期)④ 更新 tick 计数(xTaskGetTickCount)。
所以关中断期间:tick 进不来 → 时间片不轮转、延时不计时、超时不触发 → 整个调度冻结。这就是临界区里 vTaskDelay 卡死、临界区必须短的根源。
vTaskDelay(10) → 卡死(tick 被关,延时永远等不到)taskENTER_CRITICAL_FROM_ISR/taskEXIT_CRITICAL_FROM_ISR——普通版本在 ISR 里会错误恢复中断状态,破坏 Cortex-M 的高优先级中断嵌套taskENTER_CRITICAL() 保存/恢复中断状态,在 ISR 里退出时会错误地全开中断,破坏 Cortex-M 的高优先级 ISR 嵌套;FromISR 版本保存 ISR 实际状态,正确恢复(只屏蔽同级,不破坏高优先级中断)| 相邻概念 | 和本主题的关系 | 孤立理解会犯的错 |
|---|---|---|
| 原子操作 | 临界区 = 关中断实现原子性 | 以为临界区里能阻塞 |
| 互斥量 | 临界区挡中断+任务,互斥量只挡任务 | 拿临界区保护纯任务数据(杀鸡用牛刀) |
| 任务状态机 | 关中断 → tick 不来 → 调度冻结 | 以为延时照常走 |
| ISR 通信 | ISR 里要用 FromISR 版本 API | 在 ISR 用普通 API 破坏嵌套 |
2026-08-03
每主题一页,复习时只翻本目录。