我正在尝试理解记忆模型并读取5.1.2.4 Multi-threaded executions and data races
,并且被5.1.2.4(p10)
定义的释放序列概念混淆如下:
由原子对象
A
上的释放操作M
引导的释放序列是M
的修改顺序中的最大连续副作用子序列,其中第一个操作是A
,并且每个后续操作或者由执行的相同线程执行发布或是原子读 - 修改 - 写操作。
随后用于定义与5.1.2.4(p11)
同步如下:
某些库调用与另一个线程执行的其他库调用同步。特别地,对对象
A
执行释放操作的原子操作M
与对B
执行获取操作的原子操作M
同步,并且读取由A
为首的释放序列中的任何副作用所写的值。
我可以想象下面的例子:
#include <stdatomic.h>
Atomic_ int a; // <<--- M
int main(void){
atomic_store_explicit(&a, 42, memory_order_release); // <<--- A
atomic_store_explicit(&a, 442, memory_order_release);
atomic_store_explicit(&a, 242, memory_order_release);
int a_value = atomic_load_explicit(&a, memory_order_acquire);
atomic_store_explicit(&a, 242, memory_order_release);
}
我目前理解为A
是atomic_store_explicit(&a, 42, memory_order_release);
,它的释放序列是
atomic_store_explicit(&a, 442, memory_order_release);
atomic_store_explicit(&a, 242, memory_order_release);
但atomic_store_explicit(&a, 242, memory_order_release);
不包括在内,因为接下来是int a_value = atomic_load_explicit(&a, memory_order_acquire);
,这是一项收购行动。
现在来到synchronize with
,对对象M执行释放操作的原子操作A与对M执行获取操作的原子操作B同步并读取由A标题的释放序列中的任何副作用写入的值意味着A的释放序列中的所有释放操作都是通过atomic_load_explicit(&a, memory_order_acquire);
的获取操作可见的
这是正确的还是我错过了什么?
不,序列包括所有四个存储操作,因为中间加载操作由同一个线程完成。基本上对于您的示例,您不必参考同步。由于游戏中只有一个线程,“之前排序”已经为您提供了所需的所有信息。优化器甚至可以省略所有存储,但是在简化示例中是最后一个存储,即使对于原子操作也是如此。 (那么volatile
的规格中有atomic_store
,但暂时不要忘记这一点。)
我认为,释放序列概念的概念是识别不同线程的读取可以拦截存储值的点,并且在序列中的第一个存储操作之后使读取依赖性排序。为此,可以忽略线程读取其写入的值的事实。