You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARM GCC:无需volatile实现存储-存储排序的高效方案

ARM Cortex-M4 环形缓冲区共享索引的高效无volatile实现

我需要用共享索引标记共享环形缓冲区的数据写入完成,在ARM Cortex-M4平台(使用arm gcc 9.3.1,编译选项-O3)上,想找一种高效实现方式,同时避免使用不推荐的volatile关键字。

测试代码与平台差异

先看两个测试函数:

void Test1(int volatile* x) { *x = 5; }
void Test2(int* x) { __atomic_store_n(x, 5, __ATOMIC_RELEASE); }

在x86平台上,两者编译后的汇编完全一致,没有额外开销:

0000000000000000 <Test1>:
   0:   c7 07 05 00 00 00       movl   $0x5,(%rdi)
   6:   c3                      retq   
   7:   66 0f 1f 84 00 00 00    nopw   0x0(%rax,%rax,1)
   e:   00 00 

0000000000000010 <Test2>:
  10:   c7 07 05 00 00 00       movl   $0x5,(%rdi)
  16:   c3                      retq   

但在ARM Cortex-M4上,差异明显:

  • volatile版本仅生成简单的存储指令,无内存屏障:
00000000 <Test1>:
   0:   2305            movs    r3, #5
   2:   6003            str     r3, [r0, #0]
   4:   4770            bx      lr
   6:   bf00            nop
  • __atomic_store_n带__ATOMIC_RELEASE内存序会生成dmb ish数据内存屏障,带来额外开销:
00000000 <Test2>:
   0:   2305            movs    r3, #5
   2:   f3bf 8f5b       dmb     ish
   6:   6003            str     r3, [r0, #0]
   8:   4770            bx      lr
   a:   bf00            nop

解决方案:使用__ATOMIC_RELAXED内存序

要同时避免volatile和不必要的内存屏障,可以使用__atomic_store_n并指定__ATOMIC_RELAXED内存序:

void Test3(int* x) { __atomic_store_n(x, 5, __ATOMIC_RELAXED); }

该代码在ARM Cortex-M4上编译后的汇编和volatile版本完全一致,无内存屏障:

00000000 <Test3>:
   0:   2305            movs    r3, #5
   2:   6003            str     r3, [r0, #0]
   4:   4770            bx      lr
   6:   bf00            nop

关键注意事项

  • 读取共享索引时,必须使用对应的原子读取操作__atomic_load_n(x, __ATOMIC_RELAXED),确保编译器不会优化读取操作,同时保证硬件层面的可见性。
  • __ATOMIC_RELAXED适用于仅需要保证变量读写不被编译器优化、且硬件能保证可见性的场景。对于Cortex-M4单处理器系统(如中断与线程交互的环形缓冲区),这种内存序完全满足需求;如果是多处理器系统,需根据实际同步需求选择更强的内存序。

内容的提问来源于stack exchange,提问作者personal_cloud

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 19:17:03