Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

relaxed ordering of c++11 memory model

I was testing the relaxed ordering semantic of c++11 memory model on x64, and I was told that on x86/64 only store/load reordering exists, so I wrote the following program to test the relaxed ordering.

Ideally, if reordering exists(which it does), then my program should hit the case of getting "g_a == g_b == 0", but I tested it for a long time, and never get the expected results, could anybody help explain why? thanks.

[update]

sorry for forgetting to mention the compiler I used, the following code won't work when compiled with g++ 4.8.3 on Linux x86/64. thanks to @Mat's reminder, I then try compile it using clang++ 3.4.2, this time I saw the reordering, so it might be a bug in 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;
        }
    }
}
like image 414
kmalloc Avatar asked Oct 19 '22 21:10

kmalloc


1 Answers

To be able to generate assembly with the correct memory barriers, C++ ordering parameters need to be known at compile time.

The problem lies in the following statement:

memory_order order = memory_order_relaxed;

This is not a compile time constant, therefore gcc is going to assume memory_order_seq_cst and insert an mfence instruction:

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>

If you change it to:

constexpr memory_order order = memory_order_relaxed;

The relaxed parameter will take effect and the mfence is gone:

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>

If you compile with -O3 optimization, running the binary will now show the re-ordering.

like image 98
LWimsey Avatar answered Oct 23 '22 00:10

LWimsey