内存排序,指令重新排序和缺乏发生之前的关系

时间:2015-09-14 21:46:00

标签: c++ multithreading c++11

轻松下单

用std :: memory_order_relaxed标记的原子操作不是同步操作;只有线程之间共享每个原子对象的修改顺序。不同的对象相对于其他线程在它们之间没有排序;操作可以看不到。

示例 - 放宽订购

#include <atomic>
#include <thread>
#include <assert.h>
std::atomic<int> x{ 0 };
std::atomic<bool> x_is_set{ false };
std::atomic<int> counter{ 0 };
void f1()
{
    x.store(5, std::memory_order_relaxed);              // A
    x_is_set.store(true, std::memory_order_relaxed);    // B
}
void f2()
{
    while (!x_is_set.load(std::memory_order_relaxed));  // C

    if (x.load(std::memory_order_relaxed) == 5)         // D
        ++counter;                                      // E
}
int main()
{
    std::thread t1{ f1 };
    std::thread t2{ f2 };
    t1.join();
    t2.join();
    assert(counter.load() == 1);                        // F
}

线程 t1 与线程 t2 之间没有排序限制。因此,在商店完成 A 之前,可以通过 t 查看 B 中完成的商店;在这种情况下,main()中的断言 F 将触发。

此问题的明显解决方案是使 B 中的商店具有std::memory_order_release并且 C 中的加载具有std::memory_order_acquire用于同步目的。 F 中的断言似乎永远不会发生。

问题

但是,由于 A B 之间没有发生 - 之前的关系(我错了吗?),不能编译器/ optimizer / CPU重新组织函数f1()中的指令,以便 B 之前 这会导致函数f2()中的 C 评估为true,但 D 将为false;断言可以解雇。

是否存在阻止该问题发生的任何事情?

1 个答案:

答案 0 :(得分:4)

  

因为A和B之间没有发生之前的关系

错误。 [intro.multithread] / P14:

  

评估A 评估B之前发生,如果:

     
      
  • A在B之前排序,或
  •   
  • 线程发生在B之前。
  •