
目录
[1. 任务切换的底层逻辑是什么?](#1. 任务切换的底层逻辑是什么?)
[2. 什么是优先级反转?](#2. 什么是优先级反转?)
[3. 如何解决优先级翻转?](#3. 如何解决优先级翻转?)
[4. STM32 的启动流程](#4. STM32 的启动流程)
[5. 裸机开发和RTOS开发区别](#5. 裸机开发和RTOS开发区别)
[5.1 启动与运行时环境](#5.1 启动与运行时环境)
[5.2 任务模型与调度机制](#5.2 任务模型与调度机制)
[5.3 时间管理](#5.3 时间管理)
[5.4 同步与通信机制](#5.4 同步与通信机制)
[5.5 内存管理](#5.5 内存管理)
[5.6 确定性与实时性保障](#5.6 确定性与实时性保障)
[5.7 调试与可维护性](#5.7 调试与可维护性)
[6. 中断触发流程](#6. 中断触发流程)
1. 任务切换的底层逻辑是什么?
任务切换(Task Switching)本质上是CPU寄存器上下文的保存与恢复过程,由操作系统内核在特权级切换(如从用户态到内核态)时触发,依赖硬件支持(如x86的TSS、ARM的异常向量表与SPSR/ELR寄存器)。
核心动作包括:
① 保存当前任务的CPU寄存器状态(通用寄存器、栈指针、程序计数器、状态寄存器等)到其任务控制块(TCB)或内核栈;
② 加载下一个任务的寄存器状态;
③ 切换栈指针(如x86的RSP/ESP、ARM64的SP_EL0→SP_EL1);
④ 更新内存管理单元(MMU)上下文(即页表基址寄存器,如x86的CR3、ARM64的TTBR0_EL1)以实现地址空间隔离;
⑤ 执行IRET/ERET等特权返回指令完成模式切换与控制流移交。
2. 什么是优先级反转?
优先级反转(Priority Inversion)是指在实时操作系统中,一个高优先级任务因等待一个被低优先级任务持有的共享资源(如互斥锁)而被阻塞,而该低优先级任务又可能被中等优先级任务抢占,导致高优先级任务实际执行被延迟甚至无限期推迟的现象。
例如:

① L 任务正在使用某临界资源, H 任务被唤醒,执行 H 任务。但 L 任务并未执行完毕,此时临界资源还未释放。
② 这个时刻 H 任务也要对该临界资源进行访问,但 L 任务还未释放资源, 由于保护机制,H 任务进入阻塞态,L任务得以继续运行,此时已经发生了优先级翻转现象。
③ 某个时刻 M 任务被唤醒,由于 M 任务的优先级高于 L 任务, M 任务抢占了 CPU 的使用权,M任务开始运行,此时 L 任务尚未执行完,临界资源还没被释放。
④ M 任务运行结束,归还 CPU 使用权,L 任务继续运行。
⑤ L 任务运行结束,释放临界资源,H 任务得以对资源进行访问,H 任务开始运行。
3. 如何解决优先级翻转?
我们可以采用优先级继承机制,当高优先级任务 H 因等待某共享资源(被互斥锁保护),而被低优先级任务 L 阻塞时,操作系统会临时将低优先级任务 L 的优先级提升至高优先级任务 H 的优先级。
在 H 任务申请该资源的时候,由于申请不到资源会进入阻塞态,那么系统就会把当前正在使用资源的 L 任务的优先级临时提高到与 H 任务优先级相同,此时 M 任务被唤醒了,因为它的优先级比 H 任务低,所以无法打断 L 任务,因为此时 L 任务的优先级被临时提升到 H,所以当 L 任务使用完该资源了,进行释放,那么此时 H 任务优先级最高,将接着抢占 CPU 的使用权, H 任务的阻塞时间仅仅是 L 任务的执行时间,此时的优先级的危害降到了最低:

① L 任务正在使用某临界资源, H 任务被唤醒,执行 H 任务。但 L 任务并未执行完毕,此时临界资源还未释放。
② 这个时刻 H 任务也要对该临界资源进行访问,但 L 任务还未释放资源, 由于保护机制,H 任务进入阻塞态,此时由于优先级继承机制,将 L 任务的优先级拉倒和 H 任务的优先级一样。
③ 某个时刻 M 任务被唤醒,虽然 M 优先级比最初的 L 任务的优先级高,但是,此时 L 的优先级被拉到和 H 任务的优先级一样,所以 M 处于就绪态。
④ L 任务运行结束,释放临界资源,L 任务的优先级回到最初的状态。
⑤ 此时任务 H 和 M均处于就绪态,但是 H 的优先级比 M 的高,且 L 任务已经运行结束,释放临界资源,因此 H 任务得以对资源进行访问,H 任务开始运行。
⑥ M 任务比 L 任务的优先级高,M 任务执行。
4. STM32 的启动流程
① 复位向量获取与跳转;
② 栈指针(MSP)初始化;
③ 调用 Reset_Handler(复位处理函数);
④ 执行 C 运行环境初始化(__main,由 ARM C 库提供);
⑤ 初始化 .data 段(从 Flash 复制到 RAM)、清零 .bss 段、调用全局构造函数(C++);
⑥ 最终跳转至用户定义的 main() 函数。
5. 裸机开发和RTOS开发区别
裸机开发(Bare-metal Development)是指在没有操作系统(包括无内核、无任务调度、无系统调用接口)的环境下,直接面向硬件编写程序,所有资源(CPU、内存、外设寄存器、中断等)均由开发者手动管理;
RTOS开发(Real-Time Operating System Development)则是在实时操作系统(如FreeRTOS、Zephyr、RT-Thread、CMSIS-RTOS等)之上进行应用开发,由RTOS内核提供任务管理、时间管理、同步互斥(信号量/互斥量/事件组)、内存管理、中断抽象、设备驱动框架等服务,开发者通过API与内核交互,无需直接操作底层寄存器和调度逻辑。
下面从不同方面做一下对比。
5.1 启动与运行时环境
裸机:复位后执行startup汇编(设置栈指针SP、清零.bss、拷贝.data),跳转至C入口main();无用户/内核态区分,全部代码运行在特权级(如ARM Cortex-M的Thread Mode with Privileged level);中断向量表由开发者静态定义(如在flash起始地址0x0000_0000处放置ISR函数指针数组),中断服务函数(ISR)必须手动保存/恢复寄存器(若使用C语言编写且编译器不自动处理)。
RTOS:启动流程类似裸机(仍需startup),但main()中通常调用RTOS初始化函数(如FreeRTOS的xTaskCreate() + vTaskStartScheduler());调度器启动后,main()实质上退化为一个idle任务的上下文;中断向量表仍由硬件固定,但RTOS会接管部分中断(如SysTick作为系统节拍源、PendSV用于任务切换),并提供可注册的中断封装层(如FreeRTOS的xQueueSendFromISR()),确保ISR与任务间安全通信。
5.2 任务模型与调度机制
裸机:本质是单线程模型,常见实现为:
- 主循环(superloop):while(1) { do_work(); check_events(); delay_ms(); } ------ 无抢占、无优先级、无法阻塞等待事件,实时性差;
- 中断+状态机:用全局状态变量+中断标志位协调,易出现竞态(需关中断保护),状态耦合度高,难以维护;
- 协程(Coroutine):通过static局部变量或switch-case模拟挂起/恢复,非真并发,无栈隔离。
RTOS:引入抢占式/协作式多任务,每个任务拥有独立栈空间和TCB(Task Control Block)结构体(含状态、优先级、栈顶指针、阻塞列表节点等);调度器基于就绪队列(通常为按优先级组织的链表或位图)选择最高优先级就绪任务;上下文切换涉及:
- 保存当前任务寄存器(R0-R12, LR, PSR, PC等)到其栈中;
- 更新TCB中栈指针;
- 加载下一任务栈中寄存器;
- 切换SP_MSPLIM/SPSPLIM(若启用MPU);
- 切换过程由PendSV异常触发(低优先级异常,确保不打断关键ISR)。
5.3 时间管理
裸机:依赖SysTick或定时器中断,手动维护全局tick计数器,所有延时/超时逻辑需轮询判断(如if(tick - start >= ms)),精度受限于主循环周期。
RTOS:SysTick中断由RTOS接管,每节拍(如1ms)调用xTaskIncrementTick()更新系统时间,并遍历延时任务列表,将到期任务移入就绪队列;提供vTaskDelay()(相对延时)、xTaskGetTickCount()(绝对时间)等API,底层基于双向链表或时间轮(Time Wheel)优化O(1)插入/到期检测(FreeRTOS v10.3+支持时间轮)。
5.4 同步与通信机制
裸机:全靠裸共享变量+关中断(__disable_irq())或内存屏障(__DMB())实现临界区,极易出错;事件通知依赖轮询标志位或中断标志,无解耦。
RTOS:提供标准化原语:
- 信号量(Semaphore):计数型(Counting)或二值型(Binary),底层为队列+阻塞列表,take操作失败时任务挂起并加入等待列表,give操作唤醒等待列表首任务;
- 互斥量(Mutex):带优先级继承(Priority Inheritance)的二值信号量,防止优先级反转(如高优任务因等待低优任务持有的互斥量而被中优任务抢占);
- 队列(Queue):环形缓冲区+读写索引+任务等待列表,支持拷贝传递(非指针),底层使用临界区保护(进入临界区=关BASEPRI或关中断);
- 事件组(Event Group):位掩码+等待条件(AND/OR),解决多事件组合等待问题,避免多个信号量导致的优先级翻转。
5.5 内存管理
裸机:全局静态分配或简单堆管理(如malloc/free基于sbrk()),无碎片整理,无释放检查,易内存泄漏。
RTOS:提供多种堆管理方案(如FreeRTOS heap_4.c:首次适配+合并空闲块;heap_5.c:支持多段不连续RAM);所有动态分配(xTaskCreate, xQueueCreate)均走RTOS内存管理API,可配置钩子函数(vApplicationMallocFailedHook)捕获分配失败;部分RTOS支持内存池(Memory Pool)实现O(1)分配/释放,规避碎片。
5.6 确定性与实时性保障
裸机:理论上可达最优确定性(无调度开销、无中断嵌套延迟),但实际取决于开发者水平;中断响应时间 = 固定硬件延迟 + ISR执行时间(需严格控制ISR长度)。
RTOS:实时性取决于内核设计:
- 中断延迟(Interrupt Latency):从外部中断发生到ISR第一条指令执行的时间,RTOS需最小化关中断时间(如FreeRTOS只在临界区短时关BASEPRI);
- 任务切换延迟(Task Switching Latency):从高优任务就绪到其开始执行的时间,含PendSV处理+上下文切换,Cortex-M通常<1us;
- 最坏情况执行时间(WCET)分析更复杂,需考虑内核临界区、优先级继承、队列操作最坏路径等。
5.7 调试与可维护性
裸机:调试依赖JTAG/SWD单步、寄存器观察、GPIO打点;无任务状态视图,死锁/优先级反转难定位。
RTOS:支持调试插件(如SEGGER SystemView、Tracealyzer),可记录任务切换、中断、队列操作等事件,生成可视化时间轴;提供API查询任务状态(eTaskGetState)、堆栈水印(uxTaskGetStackHighWaterMark)、运行时间统计(configGENERATE_RUN_TIME_STATS)。
6. 中断触发流程
中断触发流程是指从外部设备或内部异常事件发生,到CPU暂停当前任务、保存上下文、跳转至中断服务程序(ISR)执行,最后恢复原任务的完整硬件与软件协同过程。
典型流程包括:
① 中断请求(IRQ)产生
② 中断控制器(如APIC或PIC)接收并仲裁
③ CPU在当前指令边界检查中断使能标志(IF位)
④ 若允许,CPU完成当前指令后响应中断
⑤ 自动压栈EFLAGS、CS、EIP(x86实模式/保护模式)或RFLAGS、CS、RIP(x86-64)
⑥ 根据中断向量号查IDT(中断描述符表)获取门描述符
⑦ 加载新的CS:EIP(或CS:RIP)和堆栈段(若发生特权级切换则切换到内核栈)
⑧ 执行中断服务程序
⑨ ISR末尾执行IRET(或IRETQ)指令
⑩ 恢复EFLAGS/CS/EIP并返回被中断点。

