我正在努力解决C11标准的5.1.2.4节,尤其是Release / Acquire的语义。我注意到https://preshing.com/20120913/acquire-and-release-semantics/(以及其他)指出:
...释放语义防止以程序顺序在写释放之前进行任何读或写操作,从而对写释放进行内存重新排序。
因此,针对以下内容:
typedef struct test_struct { _Atomic(bool) ready ; int v1 ; int v2 ; } test_struct_t ; extern void test_init(test_struct_t* ts, int v1, int v2) { ts->v1 = v1 ; ts->v2 = v2 ; atomic_store_explicit(&ts->ready, false, memory_order_release) ; } extern int test_thread_1(test_struct_t* ts, int v2) { int v1 ; while (atomic_load_explicit(&ts->ready, memory_order_acquire)) ; ts->v2 = v2 ; // expect read to happen before store/release v1 = ts->v1 ; // expect write to happen before store/release atomic_store_explicit(&ts->ready, true, memory_order_release) ; return v1 ; } extern int test_thread_2(test_struct_t* ts, int v1) { int v2 ; while (!atomic_load_explicit(&ts->ready, memory_order_acquire)) ; ts->v1 = v1 ; v2 = ts->v2 ; // expect write to happen after store/release in thread "1" atomic_store_explicit(&ts->ready, false, memory_order_release) ; return v2 ; }
执行的地方:
> in the "main" thread: test_struct_t ts ; > test_init(&ts, 1, 2) ; > start thread "2" which does: r2 = test_thread_2(&ts, 3) ; > start thread "1" which does: r1 = test_thread_1(&ts, 4) ;
因此,我希望线程“ 1”具有r1 == 1,线程“ 2”具有r2 = 4。
我希望是因为(遵循第5.1.2.4节第16和18段:
但是,我完全有可能不理解该标准。
我观察到为x86_64生成的代码包括:
test_thread_1: movzbl (%rdi),%eax -- atomic_load_explicit(&ts->ready, memory_order_acquire) test $0x1,%al jne <test_thread_1> -- while is true mov %esi,0x8(%rdi) -- (W1) ts->v2 = v2 mov 0x4(%rdi),%eax -- (R1) v1 = ts->v1 movb $0x1,(%rdi) -- (X1) atomic_store_explicit(&ts->ready, true, memory_order_release) retq test_thread_2: movzbl (%rdi),%eax -- atomic_load_explicit(&ts->ready, memory_order_acquire) test $0x1,%al je <test_thread_2> -- while is false mov %esi,0x4(%rdi) -- (W2) ts->v1 = v1 mov 0x8(%rdi),%eax -- (R2) v2 = ts->v2 movb $0x0,(%rdi) -- (X2) atomic_store_explicit(&ts->ready, false, memory_order_release) retq
并且提供
R1和X1以此顺序发生,这给出了我期望的结果。
但是我对x86_64的理解是,读取与其他读取按顺序发生,而写入与其他写入按顺序发生,但是读取和写入可能不会彼此按顺序发生。这意味着X1可能会在R1之前发生,甚至X1,X2,W2,R1也可能以该顺序发生-我相信。 [这似乎极不可能,但是如果R1被某些缓存问题阻止了?]
请:我不明白什么?
[我注意,如果将ts->ready
的加载/存储更改为memory_order_seq_cst
,则为存储生成的代码为:
xchg %cl,(%rdi)
这与我对x86_64的理解一致,并且将给出我期望的结果。
我正在努力解决C11标准的5.1.2.4节,尤其是Release / Acquire的语义。我注意到https://preshing.com/20120913/acquire-and-release-semantics/(以及其他)...
x86的内存模型基本上是顺序一致性加存储缓冲区(带有存储转发)。因此,每个商店都是一个release-store 1
。这就是为什么只有seq-cst存储区需要任何特殊说明的原因。 (C/C++11 atomics mappings to asm)。此外,https://stackoverflow.com/tags/x86/info包含一些指向x86文档的链接,包括a formal description of the x86-TSO memory model(对于大多数人来说基本上是不可读的;需要花很多时间才能得出结论)。