我从以下示例中获取了有关std::memory_order_seq_cst的示例:
http://en.cppreference.com/w/cpp/atomic/memory_order

#include <thread>
#include <atomic>
#include <cassert>

std::atomic<bool> x = {false};
std::atomic<bool> y = {false};
std::atomic<int> z = {0};

void write_x()
{
    x.store(true, std::memory_order_seq_cst);
}

void write_y()
{
    y.store(true, std::memory_order_seq_cst);
}

void read_x_then_y()
{
    while (!x.load(std::memory_order_seq_cst))
        ;
    if (y.load(std::memory_order_seq_cst)) {
        ++z;
    }
}

void read_y_then_x()
{
    while (!y.load(std::memory_order_seq_cst))
        ;
    if (x.load(std::memory_order_seq_cst)) {
        ++z;
    }
}

int main()
{
    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);  // will never happen
}

Acquire/Release versus Sequentially Consistent memory order问题中也提到了此示例。

我的问题是线程c和线程d怎么可能看到不同的东西?如果可能,为什么下面的这个简单示例始终得出z = 3?例如,线程b可能会说:“即使线程a已经完成,我仍然看到0,所以z再次变为0 + 1”。
#include <atomic>
#include <iostream>

std::atomic<int> z = {0};

void increment()
{
    z.fetch_add(1, std::memory_order_relaxed);
}
int main()
{
    std::thread a(increment);
    std::thread b(increment);
    std::thread c(increment);
    a.join(); b.join(); c.join();
    std::cout << z.load() << '\n';
}

最佳答案

因此,通过在注释中看到不同的内容,您的意思是线程C看到x == 1,y == 0,线程D看到x == 0和y == 1。具有顺序一致性是否可能?

让我们假设这个总顺序(修改是这些符号存储状态之间的转换):

{x==0,y==0} : S0
{x==1,y==0} : S1
{x==1,y==1} : S2

当我们说“see”时,是指线程潜在地执行负载。一个线程不能同时执行两个加载。那么,线程C看到x == 1 然后看到y == 0以及线程D看到x == 0 然后看到y == 1的可能性如何?线程C在内存处于状态S1时执行两次加载,线程D在状态S0处看到x,然后在状态S2处看到y

在您的示例代码中,发生的情况是线程C加载x然后加载y,线程D重复加载y,直到它为true然后加载x。因此,在y == 1之后,可以保证x==1处于此总顺序。

正如Minee在其评论中所说,如果使用顺序一致性存储顺序来代替获取/释放存储顺序,则不会有什么期望:获取/释放语义并不意味着任何总排序,而且在存储与存储之间的关系之前不会发生任何事情。 x并将其存储到y。因此断言z.load()!=0可能会触发。

08-28 10:18