6

来自http://en.cppreference.com

放宽排序 标记为 std::memory_order_relaxed 的原子操作不是同步操作,它们不对内存进行排序。它们只保证原子性和修改顺序的一致性。例如,x 和 y 最初为零,

// Thread 1:
r1 = y.load(memory_order_relaxed); // A
x.store(r1, memory_order_relaxed); // B
// Thread 2:
r2 = x.load(memory_order_relaxed); // C 
y.store(42, memory_order_relaxed); // D

允许产生 r1 == r2 == 42,因为尽管 A 在 B 之前排序并且 C 在 D 之前排序,但没有什么可以阻止 D 在 y 的修改顺序中出现在 A 之前,并且 B 在修改中出现在 C 之前x 的顺序。

问题:是什么赋予上述代码属性A 在 B 之前排序而C 在 D 之前排序

编辑:

int A, B;

void foo()
{
    A = B + 1; (A)
    B = 0; (B)
}

导致

$ gcc -O2 -S -masm=intel foo.c
$ cat foo.s
        ...
        mov     eax, DWORD PTR B
        mov     DWORD PTR B, 0
        add     eax, 1
        mov     DWORD PTR A, eax
        ...

在带有 -02 选项的 GCC 4.6.1 下

所以我们清楚地看到(A)和(B)已经切换了

4

3 回答 3

6

sequenced-before(与happens -before不同)关系并不特定于多线程。它们也发生在单线程程序中。任何以分号结尾的表达式都在下一个之前排序,因此在这种情况下A是在之前BC之前排序的,D因为它们中的每一个都是完整的表达式。

从标准1.9 程序执行 14

与完整表达式关联的每个值计算和副作用在与要评估的下一个完整表达式关联的每个值计算和副作用之前排序。

你可以在这里找到解释:

评估顺序

于 2014-12-13T20:20:15.680 回答
1

“Sequenced-before”适用于程序的可见可观察行为。编译器可以自由地以它想要的任何方式实现该行为;只要可见行为相同,它就可以重新排序对内存的写入或完全消除它们。

于 2014-12-14T01:05:14.040 回答
-3

这个问题无法回答。没有标准的线程语义,故事结束。

说有标准化的线程语义,或者任何程序的任何语义,都是骗局。

于 2020-01-21T19:46:24.137 回答