不同处理器上acquire/release内存顺序的理解与疑问确认
关于C++原子操作中Acquire/Release内存顺序的解答
一、你的理解是否正确?
你的第一点理解准确:
- Acquire/Release确实会阻止线程内部的部分重排序:
- 带
memory_order_acquire的加载操作,当前线程中所有后续的读、写操作都不能被重排到该加载操作之前; - 带
memory_order_release的存储操作,当前线程中所有之前的读、写操作都不能被重排到该存储操作之后。
- 带
第二点理解需要修正:
- 不是“确保所有acquire加载操作在release存储操作之后执行”,而是当线程B的acquire加载操作读取到线程A的release存储操作写入的值时,才会在两者之间建立同步关系:线程A中release存储之前的所有内存写入(包括非原子和松弛原子操作),对线程B来说都是可见的,且线程A的release操作“先行发生于”线程B的acquire操作。如果线程B的加载没读到线程A存储的值,这种同步关系就不会建立。
二、强序系统中无需显式指定内存顺序就能保证加载在存储之后?
答案是否定的,原因如下:
- 编译器优化层面:强序系统的CPU本身不会做某些重排,但编译器可能会进行指令重排优化。显式指定
memory_order_acquire和memory_order_release是告诉编译器禁止特定的重排(比如不能把非原子存储移到release存储之后,不能把非原子加载提前到acquire加载之前)。如果不指定,编译器可能会破坏预期的内存顺序。 - “大多数操作”≠所有操作:强序系统中也存在不遵循默认强序的操作(比如x86上的非对齐内存访问、部分特殊指令),而且如果原子操作使用
memory_order_relaxed,即使在x86上也不会自动获得release-acquire的保证。 - 同步关系的前提不变:即使在强序系统中,acquire和release的同步仍然依赖“线程B读取到线程A写入的值”这个前提,不是所有加载操作都会自动在所有存储操作之后执行。
内容的提问来源于stack exchange,提问作者Steve Zhang
相关产品推荐
相关产品推荐

