关于用asm volatile内存破坏子替代volatile全局变量的编译器行为疑问
关于Cortex-M4上GCC内存破坏子与volatile的疑问
在搭载Cortex-M4内核的嵌入式MCU上使用GCC编译C语言程序时,我遇到了线程数据同步的疑问:在不使用互斥锁的场景下,ChatGPT始终建议用volatile全局变量而非编译器内存破坏子,这让我不解。我的思路如下:
// non-volatile global variable bool g_flag = false; // thread 1 g_flag = true; // 编译器可能优化为"mov r0, #1" asm volatile("" ::: "memory"); // 我认为此行前编译器会生成"str r0, [g_flag]" // thread 2 asm volatile("" ::: "memory"); // 我认为此行后编译器不会使用g_flag的寄存器缓存值 while (!g_flag) // 我认为编译器会生成类似"ldr r0, [g_flag]; cmp r0, #0; bne loop_end"的代码 // --ldr指令始终存在 { ... asm volatile("" ::: "memory"); // 此处也添加 } ...
根据GCC文档:
"memory"
"memory"破坏子告知编译器,汇编代码会对输入输出操作数之外的内存进行读写(例如访问输入参数指向的内存)。为确保内存值正确,GCC可能需要在执行asm前将特定寄存器值刷新到内存。此外,编译器不会假设asm前从内存读取的值在asm后保持不变,会按需重新加载。使用"memory"破坏子可有效形成编译器的读写内存屏障。
基于上述文档,我的理解是:编译器会假设内存任意部分可能被读写,因此会在内存破坏子前将寄存器缓存的变量刷入内存(通过str指令),在内存破坏子后重新从内存加载寄存器缓存的变量。因此只要在需要的位置使用内存破坏子,就无需将全局变量声明为volatile。
请判断我的理解是否正确,若错误请从汇编代码层面解释原因。注:本问题聚焦编译器行为,已知涉及获取/释放序时需硬件屏障,但与此问题无关。
内容的提问来源于stack exchange,提问作者robbie fan
相关产品推荐
相关产品推荐

