Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory ordering, instruction reordering and lack of happens-before relationship

Relaxed ordering

Atomic operations tagged with std::memory_order_relaxed are not synchronization operations; only the modification order of each individual atomic object is shared between threads. Different objects have no ordering between themselves relative to other threads; operations can be seen out of order.

Example – Relaxed ordering

#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
}

There are no ordering constraints between thread t1 and thread t2. Therefore, the store done in B can be seen by t2 before the store done by A; the assert F in main() will fire in that case.

The obvious solution to this issue is to make the store in B have std::memory_order_release and the load in C have std::memory_order_acquire for synchronization purposes. The assert in F would seemingly never fire.

Question

However, since there is no happens-before relationship between A and B (am I wrong?), can't the compiler/optimizer/CPU reorganize the instructions in function f1() such that B is sequenced-before A? This would cause C in function f2() to evaluate to true, but D would be false; the assert could fire.

Is there anything preventing that issue from arising?

like image 243
bku_drytt Avatar asked Sep 05 '25 03:09

bku_drytt


1 Answers

since there is no happens-before relationship between A and B

Wrong. [intro.multithread]/p14:

An evaluation A happens before an evaluation B if:

  • A is sequenced before B, or
  • A inter-thread happens before B.
like image 119
T.C. Avatar answered Sep 10 '25 03:09

T.C.