C++ 顺序一致性并且发生在关系之前

zxy*_*122 1 c++ multithreading atomic memory-model stdatomic

    #include <atomic>
    #include <thread>
    #include <assert.h>
    std::atomic<bool> x,y;
    std::atomic<int> z;
    void write_x()
    {
        x.store(true,std::memory_order_seq_cst); // 1
    }
    void write_y()
    {
        y.store(true,std::memory_order_seq_cst); // 2
    }
    void read_x_then_y()
    {
        while(!x.load(std::memory_order_seq_cst)); // 3
        if(y.load(std::memory_order_seq_cst)) // 4
            ++z;
    }
    void read_y_then_x()
    {
        while(!y.load(std::memory_order_seq_cst)); // 5
        if(x.load(std::memory_order_seq_cst)) // 6
            ++z;
    }
    int main() {
        x=false;
        y=false;
        z=0;
        std::thread a(write_x);
        std::thread b(write_y);
        std::thread c(read_x_then_y);
        std::thread d(read_y_then_x);
        a.join();
        b.join();
        c.join();
        d.join();
        assert(z.load()!=0); 
    }
Run Code Online (Sandbox Code Playgroud)

在《C++ Concurrency in Action》一书中,作者在谈论顺序一致性时给出了这个例子,并说assert永远不能触发,因为

[1] 或 [2] 必须首先发生...并且如果一个线程看到 x==true 然后随后看到 y==false,这意味着按照总顺序,对 x 的存储发生在对 y 的存储之前。

我知道所有顺序一致的原子操作存在一个全局总顺序,如果一个线程看到 x == true,则意味着操作 1 与操作 3 同步,并且也在操作 3 之前发生,但我的问题是该线程是否随后看到 y == false,为什么它意味着1发生在2之前?是否有可能操作 2 在操作 1 之前发生,但操作 4 没有看到该值发生变化?

use*_*522 6

是否有可能操作 2 在操作 1 之前发生,但操作 4 没有看到该值发生变化?

请务必注意此处的术语。您在这里所说的“发生之前并不是内存模型描述中使用的发生之前关系。您在这里的意思是在顺序一致操作的总顺序中发生在之前

假设我们写的X < Y意思是,按照总顺序,操作X发生在操作之前。Y你考虑一下情况2 < 1。为了4观察存储之前的值,我们还需要4 < 2. 还有一个条件是3观察存储的值,否则4永远不会达到,所以也1 < 3。最后我们有3是sequence-before 的4并且总顺序必须与之一致,所以也是3 < 4

总而言之:

2 < 1
4 < 2
1 < 3
3 < 4
Run Code Online (Sandbox Code Playgroud)

如果您现在尝试创建1, 2, 3, 4满足这些条件的全序,您会发现它不起作用。要证明这一点,请参阅2 < 11 < 3暗示2 < 3,其中 和3 < 4暗示2 < 4。这自相矛盾4 < 2

不存在满足条件的全序,因此这不是可能的结果。必须看到商店之后的4价值,这实际上是我上面使用的连锁店推导出来的。(如果你仔细检查用上面的条件替换不会产生任何其他矛盾,所以你还可以找到一个真正满足所有条件的全序。)4 < 24 < 22 < 4