【问题标题】:Memory ordering, instruction reordering and lack of happens-before relationship内存排序、指令重新排序和缺少发生前的关系
【发布时间】:2015-12-11 00:35:49
【问题描述】:

轻松排序

用 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 之间没有排序限制。因此,t2可以先看到B做的store,然后A做的store;在这种情况下,main() 中的断言 F 将触发。

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

问题

但是,由于 A 和 B 之间没有 happens-before 关系(我错了吗?),编译器不能/optimizer/CPU 重新组织函数 f1() 中的指令,使得 B 是 sequenced-before A?这将导致函数f2() 中的C 计算为true,但D 将是false;断言可以触发。

有什么东西可以阻止这个问题的出现吗?

【问题讨论】:

  • A和B在同一个线程中,并且A在B之前排序,所以A在B之前发生。
  • A 在 B 之前发生,但是从另一个线程中 B 的副作用可能在 A 的副作用之前可见。
  • 我认为即使 A 在 B 之前排序,如果 A 没有将依赖项带入 B,则不存在先于关系。那么,它们在之前排序这一事实是否意味着存在先发生关系?
  • @bku_drytt 那么任何程序将如何工作?您如何使任何副作用可见?

标签: c++ multithreading c++11


【解决方案1】:

因为A和B之间没有happens-before关系

错了。 [intro.multithread]/p14:

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

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

【讨论】:

    猜你喜欢
    • 2013-04-19
    • 2021-12-02
    • 2023-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-04
    • 2016-12-27
    • 1970-01-01
    相关资源
    最近更新 更多