在C ++ 11中获取/释放VS顺序一致性?

时间:2018-05-22 08:18:23

标签: c++11 atomic memory-model memory-barriers

#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_release);
}

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

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

void read_y_then_x()
{
    while (!y.load(std::memory_order_acquire))
        ;
    if (x.load(std::memory_order_acquire)) {
        ++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);
}

如果我将seq_cst替换为cppreference's last example中的获取/释放, assert(z.load() != 0)会失败吗?

  • Seq_CST可以阻止StoreLoad重新排序,但代码没有。
  • 获取可以阻止LoadLoad重新排序。
  • 发布可以阻止StoreStore重新排序。

2 个答案:

答案 0 :(得分:1)

获取/发布保证的主要属性是单个修改顺序。它仅保证ab的{​​{1}}和c先前的行为(如果他们从加载中看到d时会被truea观察到。

这个明显的例子是在多CPU(物理套接字)系统上。 Die 1具有核心A运行线程c和核心C运行线程b。 Die 2具有核心B运行线程d和核心D运行线程a。与访问片上高速缓存的内存操作相比,两个套接字之间的互连具有较长的延迟。

bx在相同的挂钟时间运行。 C是A上的模具,因此可以立即看到商店y,但是互连会将商店的观察延迟到y,因此它会看到旧值。类似地,D与B一起死亡,因此它将商店看作x,但将商店错过@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_homepage); Log.v("MYDEV", "oncreate"); presenter.start(); }

如果您具有顺序一致性,则需要一些协调来强制执行总订单,例如“当互连同步缓存时C和D被阻止”。

答案 1 :(得分:1)

是的,如果您使用z.load() == 0 / acquire订单,代码中可能会release。对xy的独立写入之间没有发生过 - 之前的关系。这个例子并不是巧合,而是专门用来说明获取/释放不足的情况。

这有时称为IRIW(独立写入的独立读取),并且倾向于在某些硬件订购模型中被掩盖。特别是,仅根据可能的负载,负载存储,商店存储等定义的存储器模型,重新排序并不能说任何关于IRIW的方式。在x86内存模型中,不允许IRIW重新排序,因为有一个条款解释了存储具有总订单而所有处理器以相同的顺序查看存储。

我不知道当使用获取和释放所需的障碍和/或指令时,是否有任何常用的CPU承认IRIW重新排序,但如果有人这样做,我不会感到惊讶。