
文章目录1. 核心痛点多任务并发与数据竞争2. 手腕一全局临界区基于 Cortex-M32.1 核心原理2.2 完美嵌套设计状态保存与恢复2.3 源码实现 (switch.c)3. 手腕二调度锁基于计数器拦截3.1 核心原理3.2 完美嵌套设计计数器机制3.3 源码实现switch.c3.4 调度器内部的劝退拦截switch.c4. 终极对比临界区 VS 调度锁5. 总结建议1. 核心痛点多任务并发与数据竞争在单核 CPU 的 RTOS 中高优先级任务或中断ISR的抢占机制会导致共享全局变量出现“更新丢失”Race Condition。并发灾难任务 A 读出变量到局部变量后被抢占抢占者修改了全局变量任务 A 恢复后用旧值强行回写导致中间的修改被无情覆盖。解决核心必须保证“读-改-写”原子化为这段核心代码构建临界区。RTOS 提供了两种基础保护手腕全局临界区关中断与调度锁禁调度。2. 手腕一全局临界区基于 Cortex-M32.1 核心原理通过屏蔽全局中断使得硬件定时器SysTick及所有外设中断无法触发从根本上杜绝任务切换与抢占。无论是“任务打断任务”还是“中断打断任务”全部失效。2.2 完美嵌套设计状态保存与恢复如果嵌套调用函数简单的“无脑开/关”会导致内层函数退出时错误打开中断导致外层临界区提前敞开。tinyOS采用保存/恢复 PRIMASK 寄存器的方式解决嵌套。2.3 源码实现 (switch.c)uint32_ttTaskEnterCritical(void)// 进入临界区{uint32_tstatus__get_PRIMASK();// 1. 读取并保存当前中断状态状态拍照__disable_irq();// 2. 关闭全局中断returnstatus;// 3. 返回原状态用于后续恢复}voidtTaskExitCritical(uint32_tstatus)// 退出临界区{__set_PRIMASK(status);// 将之前保存的状态恢复回去}逻辑闭环若外层是开着的内层退出就恢复为开若外层已经是关的内层退出依然保持关闭完美支持套娃调用。3. 手腕二调度锁基于计数器拦截3.1 核心原理不关闭全局中断允许高优先级外设中断正常响应保证系统实时性但在中断触发的调度器中拦截任务切换。当前任务就像挂上了免打扰牌瞬间返回并继续执行后面的业务代码。3.2 完美嵌套设计计数器机制引入全局变量schedLockCount上锁则自增解锁则自减。只有当计数器归零时才真正恢复调度能力。3.3 源码实现switch.c// 调度锁上锁挂免打扰牌voidtTaskSchedDisable(void){uint32_tstatustTaskEnterCritical();// 保护临界区变量自身if(schedLockCount255)schedLockCount;tTaskExitCritical(status);}// 调度锁解锁摘免打扰牌voidtTaskSchedEnable(void){uint32_tstatustTaskEnterCritical();if(schedLockCount0){if(--schedLockCount0)tTaskSched();// 计数归零说明最外层也解锁了// 主动触发调度刚才有谁找我}tTaskExitCritical(status);}3.4 调度器内部的劝退拦截switch.c当 SysTick 心跳触发或其它任务就绪调用tTaskSched时调度器第一步就会查牌voidtTaskSched(void){uint32_tstatustTaskEnterCritical();if(schedLockCount0)// 拦截发现调度锁已上锁{tTaskExitCritical(status);return;// 极速劝退直接退出原任务继续霸占CPU}// ... 后续真正的上下文切换代码如 tTaskSwitch...}4. 终极对比临界区 VS 调度锁特性全局临界区tTaskEnterCritical调度锁tTaskSchedDisable打断机制连中断也一起干掉绝对安全允许中断响应但任务换不走任务间互斥完全有效因 SysTick 中断被掐断无法切换完全有效通过底层调度拦截实现互斥实时性影响极高。关中断时间过长会导致外设中断丢失较低。只延迟了任务切换不耽误硬件响应适用场景任务与中断共享变量、操作底层寄存器任务与任务共享变量、耗时较长的代码段5. 总结建议短小精悍用临界区如果只是保护单行寄存器赋值或shareCount直接关中断耗时仅几个时钟周期效率最高。长篇大论用调度锁如果两个任务之间共享变量且临界区内有耗时较长的循环或业务逻辑必须使用调度锁在不牺牲系统外设响应速度的前提下完成任务互斥。