是否有一个真正有效的例子显示了商店负载重新排序对x86_64的副作用?

时间:2017-03-20 16:37:26

标签: c++ multithreading c++11 concurrency x86-64

  • 众所周知,在x86_64上可以进行Store-Load重新排序,如果在Store&加载不是MFENCE

Intel® 64 and IA-32 Architectures

  

8.2.3.4负载可能会与较早的商店重新排序到不同的位置

  • 也知道,在这样的例子中可以是Store-Load重新排序

c.store(relaxed)< - > b.load(seq_cst)https://stackoverflow.com/a/42857017/1558037

// Atomic load-store
void test() {
    std::atomic<int> b, c;
    c.store(4, std::memory_order_relaxed);          // movl 4,[c];
    int tmp = b.load(std::memory_order_seq_cst);    // movl [b],[tmp];
}

可以重新排序:

// Atomic load-store
void test() {
    std::atomic<int> b, c;
    int tmp = b.load(std::memory_order_seq_cst);    // movl [b],[tmp];
    c.store(4, std::memory_order_relaxed);          // movl 4,[c];
}

因为x86_64上没有MFENCE

但有没有一个真正有效的例子显示了商店负载重新排序对x86_64的副作用?

示例,在使用Store(seq_cst), Load(seq_cst)时显示正确的结果,但在使用Store(relaxed), Load(seq_cst)时显示错误的结果。

或者x86_64上是否允许存储加载重新排序,因为它无法检测到并显示在程序中?

2 个答案:

答案 0 :(得分:1)

是的,在C ++ 11和x86_64上有一个Store-Load重新排序的例子。

首先,我们严格证明代码的正确性。然后在这段代码中,我们将删除STORE和LOAD之间的mfence障碍,并看到算法崩溃。

有自定义锁定(自旋锁定),没有CAS / RMW操作,只有Load&amp;存储有限数量的线程,其中每个线程编号为0-4:

// example of Store-Load reordering if used: store(release)
struct lock_t {
    static const size_t max_locks = 5;
    std::atomic<int> locks[max_locks];

    bool lock(size_t const thread_id) {

        locks[thread_id].store(1, std::memory_order_seq_cst);                     // Store
        // store(seq_cst): mov; mfence;
        // store(release): mov;

        for (size_t i = 0; i < max_locks; ++i)
            if (locks[i].load(std::memory_order_seq_cst) > 0 && i != thread_id) { // Load
                locks[thread_id].store(0, std::memory_order_release);   // undo lock
                return false;
            }
        return true;
    }

    void unlock(size_t const thread_id) {
        locks[thread_id].store(0, std::memory_order_release);
    }
};
  1. 首先我们严格证明算法的正确性,acquire-release - 语义:
  2. enter image description here

    1. 然后我们将展示如何制定锁定算法 - 结果应为:20000

    2. C ++ diff:

      enter image description here

      1. 然后我们展示了汇编代码之间的区别:

      2. Asm x86_64 diff:

        enter image description here

        因为严格证明“好”算法是正确的。因为我们发现“坏”算法无法正常工作(结果19976不等于20000)。它们之间的唯一区别是 - STORE和LOAD之间的障碍mfence。因此,我们提供了发生Store-Load重新排序的算法。

        此外,至少有一个Store-Load重新排序示例 - 有点像我们的示例Can x86 reorder a narrow store with a wider load that fully contains it?

答案 1 :(得分:0)

编译器不会在std::memory_order_seq_cst操作周围重新排序加载和存储。

CPU可能会对这些进行重新排序,因为存储和加载之间没有依赖关系。换句话说,商店可能在加载后完成。但是,没有办法观察差异,因为负载没有副作用。