第二批 FreeRTOS / RTOS 八股 · 复习总结(8 主题)
使用说明:先自测「判别规则速查表」,遮住右列自答;再做「综合练习题」,最后对答案。
面试前只翻本目录,不背题。
一、判别规则速查表(遮右自测)
| # | 主题 | 一句话判别规则 |
| -- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 24 | 任务状态机 | 在跑=Running;排队等 CPU=Ready;主动等事件/延时=Blocked(自动醒、有超时);被外部挂起=Suspended(手动醒、无超时) |
| 25 | 抢占 vs 时间片 | 高优先级就绪→抢占(跨级);同优先级 tick 到点→时间片;低优先级就绪→永不切换 |
| 26 | 优先级反转 | 高等待 + 低持有 + 中插队(三者齐)= 反转;解决=互斥量(优先级继承),别拿二值信号量当锁 |
| 27 | 临界区 | 数据被中断/硬件碰→关中断(临界区);只被任务碰→互斥量/挂起调度器;临界区禁阻塞、要短、多核只关本核 |
| 28 | IPC 选型 | 数据→队列;事件→信号量;资源→互斥量;多事件组合→事件组;一对一简单→任务通知 |
| 29 | RTOS 任务同步方式 | 一对一→任务通知;多条件组合(AND/OR)→事件组;计数/资源/多接收者→信号量 |
| 30 | ISR 通信 | 会阻塞或要任务身份(互斥量)→ ISR 禁用;其余发送/通知一律 FromISR 版 |
| 31 | 栈估算 | 栈 =最坏路径峰值(局部+调用帧+库函数+中断嵌套)× 1.5~2;HighWaterMark 留 20%+ 余量 |
二、易混对比集中营(高频考点串讲)
任务四种状态
|
Blocked |
Suspended |
| 原因 |
主动等待事件(延时/信号量/队列) |
被外部挂起 |
| 恢复 |
事件来了自动回 Ready |
必须 vTaskResume |
| 有超时吗 |
有 |
无 |
抢占 vs 时间片
|
抢占 |
时间片 |
| 触发 |
更高优先级就绪 |
tick 到点(同优先级) |
| 作用 |
跨优先级 |
同优先级内部 |
| 目的 |
最高优先级先跑 |
公平轮流 |
二值信号量 vs 互斥量
|
二值信号量 |
互斥量 |
| 优先级继承 |
❌ |
✅ |
| 所有权 |
任何人可释放 |
只能获取者释放 |
| 用途 |
事件通知/同步 |
保护共享资源 |
| 反转风险 |
有 |
继承缓解 |
优先级继承 vs 优先级天花板
|
优先级继承 |
优先级天花板 |
| 机制 |
持锁者动态提到当前等待者水平 |
持锁者静态提到所有使用者最高级 |
| 优点 |
灵活、不过度 |
简单可靠 |
| 缺点 |
实现复杂、链式继承开销 |
过度提升,可能降整体实时性 |
临界区三件套
|
关中断(临界区) |
挂起调度器 |
互斥量 |
| 挡什么 |
中断+任务 |
只挡任务 |
只挡任务(等待者阻塞) |
| 中断响应 |
不能 |
能 |
能 |
| 适用 |
中断也碰的数据 |
只有任务碰 |
只有任务碰、要等锁 |
| 代价 |
中断延迟大 |
小 |
切换开销 |
IPC 五工具选型总表
| 工具 |
传什么 |
适用 |
成本 |
| 队列 |
数据 |
数据流、命令 |
中(复制) |
| 信号量 |
事件/计数 |
通知、计数 |
低 |
| 互斥量 |
无(锁) |
资源独占 |
低+继承 |
| 事件组 |
事件组合 |
多事件与/或 |
低 |
| 任务通知 |
简单信号 |
一对一唤醒 |
最低 |
普通 API vs FromISR 版
|
普通版 |
FromISR 版 |
| 阻塞吗 |
会(带超时) |
不会(失败即返) |
| 唤醒高优先级 |
立即切换 |
置pxHigherPriorityTaskWoken,中断返回后才切换 |
| 适用 |
任务上下文 |
中断/任务都可用 |
栈 vs 堆
|
栈 |
堆 |
| 存放 |
局部变量/调用帧/保存寄存器 |
malloc 动态内存 |
| 谁管 |
系统自动 |
程序员 |
| 溢出后果 |
踩坏相邻内存/任务 |
分配失败/碎片 |
三、综合练习题(答完再对答案)
判断题(对/错 + 一句话理由)
vTaskDelay(100) 之后,任务进入 Suspended 状态。答:错,是阻塞状态
- 一个任务被更高优先级任务抢占后,先进入 Ready 状态排队,不会直接回 Running。答:对,任务被更高优先级任务抢占后,先进入 Ready 状态排队,而不是阻塞和悬挂和运行。
- 两个同优先级任务轮流执行,一个的 tick 时间片用完换另一个跑——这叫抢占。答:错,是时间片轮换
- 任务 H(8) 等信号量 S,任务 L(2) 持有 S,任务 M(4) 就绪长跑 → 发生优先级反转。答:对,高优先级任务等待资源,低优先级任务持有资源,中优先级任务是就绪状态,不等待也不持有资源,发生优先级反转
- 任务 A(8) 等互斥量,B(2) 持互斥量,C(1) 就绪 → 发生优先级反转。答:错,高优先级任务等待资源,低优先级任务持有资源,中优先级任务是就绪状态,不等待也不持有资源,发生优先级反转
- 临界区里调用
vTaskDelay(10) 会正常工作,只是慢一点。答:错,临界区的本质是关闭中断,在临界区内的动作必须是微秒级别,一旦达到毫秒就会发生跑飞、死锁等, 调用vTaskDelay(10)进入阻塞,但计时器定时中断没正常工作,会发生错误。
- 数据同时被任务和中断访问时,用互斥量保护就够了。答:错,中断也要碰的数据,尽量还是要使用关中断(临界区)。
- 信号量可以把具体的数据值传给接收任务。答:错,不能,除非是计数任务等
- 经典版任务通知可以一次通知多个任务。答:错,不能,一般只能1对1通知
- ISR 里可以用带超时参数的
xQueueSend。答:错,临界区的本质是关闭中断,在临界区内的动作必须是微秒级别,一旦达到毫秒就会发生跑飞、死锁等。
- ISR 里可以给互斥量 give。答:错,互斥量要进行优先级继承,这会包含任务上下文。而在 ISR 里面只有中断上下文,不能够正常恢复现场,导致会跑飞。
- 任务栈开得越大越好,4096 words 保证永不溢出。答:错,会浪费资源
uxTaskGetStackHighWaterMark 返回的值越大,表示栈越接近溢出。答:错,返回值表示占历史最低空闲资源,越大代表空闲的资源越多,越不接近溢出。
- RTOS 里任务正跑时被中断打断,异常帧会压进当前任务自己的栈。答:对,RTOS 任务跑在 PSP(任务自己的栈),中断异常帧压进当前任务栈——这就是估算要算中断嵌套的原因。
填空题
- 任务等待一个永不发生的事件,会永久处于 ____ 状态(RTOS 经典 bug)。答:饥饿
- 需要固定周期执行(硬实时周期任务),用 ____ 而非 vTaskDelay。答:vTaskDelayUnit
- 解决优先级反转的两个机制:____(FreeRTOS 默认)和 ____。答:优先级继承,优先级天花板
- 保护共享资源用 ____;事件通知用 ____(0/1 信号)。答:互斥量,任务通知
- ISR 里通知任务必须用 ____ 结尾的 API,通过 ____ 标志在中断返回后切换。答:FromISR,pxHigherPriorityTaskWoken(本质是pdTrue)
- 任务栈估算 = ____ × 余量系数(经验 1.5~2)。答:最坏路径峰值(局部变量+调用帧+库函数+中断嵌套)
- 串口收到一个字节的数据要交给另一个任务处理 → 用 ____。答:队列
- 等"按键按下 OR 定时器到点"任一事件 → 用 ____。答:事件组
场景 / 代码判断v
- 场景:高优先级任务被中优先级任务拖住,持有资源的低优先级任务一直抢不到 CPU。识别这是什么问题,并给出解决方案。答:优先级翻转,使用互斥量的优先级继承方案或者优先级天花板方案,一般而言采用优先级继承。
- 代码错在哪:
void ISR(void) { xQueueSend(&q, &data, 10); }答:在中断中,ISR不能够使这个带阻塞的xQueueSend
- 代码会怎样:
taskENTER_CRITICAL(); vTaskDelay(10); taskEXIT_CRITICAL();答:临界区的本质是关闭中断,在临界区内的动作必须是微秒级别,一旦达到毫秒就会发生跑飞、死锁等, 调用vTaskDelay(10)进入阻塞,但计时器定时中断没正常工作,会发生错误。
- 任务栈 128 words,
uxTaskGetStackHighWaterMark 返回 20——栈要不要加大?答:用,余量系数计算得128*0.2=25.6,可知够,但任务功能需求加载时可能需要加
四、答案(已分离)
答案解析已单独存放,避免自测时不小心看到答案:
第二批复习总结-答案.md(同目录)——完成全部 26 题后再翻开对照。
复习目标:每条规则能自己讲出"为什么",不只记住结论。