x86_64架构下movl是否为原子操作?读int64全局变量是否仅返回1或10?
问题1:x86_64架构CPU上movl是不是原子操作?
movl是x86架构下的32位(4字节)数据传输指令。- 按照英特尔和AMD的x86_64架构官方手册规定:只要操作的内存地址是自然对齐、且不跨CPU缓存行(默认64字节),宽度不超过8字节的内存读写指令都是原子操作。
- 常规场景下编译器分配的全局变量都会满足自然对齐要求,这种情况
movl的读写都是原子的。只有手动指定非自然对齐、操作地址刻意不对齐的极端场景下,movl才可能因为跨缓存行出现非原子的读写。
问题2:上述场景中线程1读取到的值是否永远只会是1或者10,不存在其他可能?
要分两个层面判断:
仅考虑给出的汇编指令的硬件执行逻辑
- 你给出的线程1汇编是
movl a(%rip), %eax,仅读取全局变量的低32位,且x86_64下写32位寄存器%eax会自动清空对应64位寄存器%rax的高32位。 - 全局变量
g_some_global_variable是8字节的int64类型,默认按8字节自然对齐,线程2对它的赋值操作只要是单次对齐的8字节写,要么完全执行完成(值更新为10),要么未执行(值保持1)。 - 这种前提下线程1的32位读操作是原子的,确实只会读到1或者10的低32位,最终局部变量
a的取值就是1或10,不会出现其他中间值。
从C++程序标准和编译优化规则看
- 你的代码存在明确的数据竞争:多线程并发访问同一个非原子变量,且至少有一个线程是写操作,按照C++标准这属于未定义行为,任何运行结果都是合法的。
- 由于你没有给
g_some_global_variable加volatile限定,也没有使用std::atomic原子类型,也没有加互斥锁、内存屏障等同步逻辑,编译器完全可以在编译阶段直接优化掉内存读取操作,直接给a赋值为初始值1,根本不会执行movl读内存的指令。这种情况下线程1永远只会读到1,哪怕线程2已经修改了全局变量的值。 - 极端情况下如果编译器把线程2的8字节赋值拆分成两次32位写操作,还可能出现线程1读到高低位不匹配的异常值,不过这种情况在x86_64平台的常规编译选项下几乎不会出现。
内容的提问来源于stack exchange,提问作者ddwolf
相关产品推荐
相关产品推荐

