Cortex M3(STM32) Thumb2架构下自增自减操作非原子性问题咨询
自增操作非原子性问题分析
首先明确:你看到的8/16/32位变量自增不符合预期,核心原因是C语言的++操作在当前编译结果下被拆分为读-改-写多步独立指令,不属于CPU层面的单步原子操作,和变量是否对齐没有关系。
操作步骤拆解
你提供的三种宽度变量的自增汇编逻辑完全一致,都分为三个独立执行阶段:
- 读内存:将变量的值从RAM加载到CPU寄存器(对应
LDRB/LDRH/LDR指令) - 改数值:在寄存器侧完成加1计算以及对应位宽的无符号扩展处理(对应
UXTB/UXTH/ADDS指令) - 写内存:将寄存器内的计算结果写回RAM对应的变量地址(对应
STRB/STRH/STR指令)
线程安全问题触发逻辑
以32位变量自增为例,出现计数错误的典型流程如下:
- 初始时
dbgIdx32 = 1000,线程A先执行,刚完成「读内存」步骤,寄存器R3里的值是1000,还没执行加1操作,此时被更高优先级的中断/线程B抢占 - 线程B完整执行完一次自增操作,内存中
dbgIdx32被更新为1001 - 线程A恢复执行,继续对寄存器里的1000加1得到1001,再将1001写回内存
- 最终
dbgIdx32的值为1001,而不是预期的1002,出现一次计数丢失
变量对齐不解决问题的原因
你提到的变量对齐仅能保证单条内存读写指令(LDR/STR等)的执行是原子的,不会触发总线的多次传输,但整个自增操作是多条独立指令的组合,指令之间随时可能被其他上下文打断,因此对齐无法保证整个自增操作的原子性。
可行的优化方案
- 临界区方案:操作前关闭全局中断,操作完成后恢复中断,适合嵌入式场景下的轻量级计数操作,也就是你目前已知的方案
- 原生原子指令方案:使用ARM架构提供的LDREX/STREX独占访问指令对,或者调用SDK封装好的原子操作接口,不需要关中断即可保证操作的原子性
内容的提问来源于stack exchange,提问作者Oliver Richter
相关产品推荐
相关产品推荐

