【问题标题】:relaxed ordering of c++11 memory modelc++11内存模型的宽松排序
【发布时间】:2014-11-23 08:03:16
【问题描述】:

我在 x64 上测试 c++11 内存模型的宽松排序语义,我被告知在 x86/64 上只存在存储/加载重排序,所以我编写了以下程序来测试宽松排序。

理想情况下,如果存在重新排序(确实如此),那么我的程序应该会遇到“g_a == g_b == 0”的情况,但是我测试了很长时间,但从未得到预期的结果,可能有人帮忙解释一下为什么吗?谢谢。

[更新]

抱歉忘记提及我使用的编译器,以下代码在 Linux x86/64 上使用 g++ 4.8.3 编译时将不起作用。感谢@Mat的提醒,然后我尝试使用clang++ 3.4.2编译它,这次我看到了重新排序,所以它可能是g++中的一个错误。

#include <iostream>
#include <thread>
#include <atomic>

using namespace std;
atomic<int> g_a, g_b;
atomic<int> g_x, g_y;
memory_order order = memory_order_relaxed;

void bar1()
{
    register int t = 0;
    g_x.store(42, order);
    t = g_y.load(order);
    g_a = t;
}

void bar2()
{
    register int t = 0;
    g_y.store(24, order);
    t = g_x.load(order);
    g_b = t;
}

int main()
{
    for (int i = 0; i < 1000000; ++i)
    {
        g_a = 0; g_b = 0;
        g_x = 0; g_y =0;
        thread t1(&bar1);
        thread t2(&bar2);

        t1.join();
        t2.join();
        if (g_a.load(order) == 0 && g_b.load(order) == 0)
        {
            cout << "g_a == g_b == 0" << endl;
        }
    }
}

【问题讨论】:

  • 我没有看过你的代码,但你应该知道 x86 提供了比你可能需要的更强大的保证。
  • 我知道这一点,这就是为什么我选择“存储/加载”的重新排序类型进行测试,我知道这是肯定存在的。
  • FWIW,在 Linux/x86_64 上使用 clang++ 3.5(-O3 -std=c++11 -pthread 使用 libstdc++ 4.7.3)构建时,我看到了您的“预期”结果。在 GCC 4.9.2 中没有看到这一点。使用 libc++ 的 clang++ 没有看到它。

标签: c++11 memory-model


【解决方案1】:

为了能够生成具有正确内存屏障的程序集,需要在编译时知道 C++ 排序参数。

问题出在以下语句:

memory_order order = memory_order_relaxed;

这不是编译时间常数,因此gcc 将假定memory_order_seq_cst 并插入mfence 指令:

Dump of assembler code for function bar1():
   0x0000000000400fc0 <+0>:     movl   $0x2a,0x20128a(%rip)        # 0x602254 <g_x>
   0x0000000000400fca <+10>:    mfence
   0x0000000000400fcd <+13>:    mov    0x20127d(%rip),%eax        # 0x602250 <g_y>

如果你把它改成:

constexpr memory_order order = memory_order_relaxed;

松弛参数生效,mfence消失:

Dump of assembler code for function bar1():
   0x0000000000400fc0 <+0>:     movl   $0x2a,0x201286(%rip)        # 0x602250 <g_x>
   0x0000000000400fca <+10>:    mov    0x20127c(%rip),%eax        # 0x60224c <g_y>

如果您使用-O3 优化进行编译,现在运行二进制文件将显示重新排序。

【讨论】:

  • 哇,这很有道理。谢谢。也许编译器应该发出一些警告。
  • 是的,那将是理想的。不确定是否可以,因为您没有违反语言规则
猜你喜欢
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 2015-08-03
  • 2020-10-10
  • 1970-01-01
  • 2020-01-06
  • 2012-08-25
  • 1970-01-01
相关资源
最近更新 更多