Whilst trying out text book examples of using memory order tags with atomics I realized that even with std::memory_order_relaxed
, examples like the one bellow work the same as if stronger memory order tags had been used. On googling I find out its because x86 already guarantees a relatively strongly ordered memory model. My question is when writing atomics based concurrency code on x86 how am I supposed to know if the code I have written is “safe” when even if I mess up the memory order tags it still works fine?
by "safe" i mean will work as intended without the x86 automatic strong memory ordering.
#include <atomic>
#include <thread>
#include <assert.h>
std::atomic<bool> x, y;
std::atomic<int> z;
void write_x_then_y()
{
x.store(true, std::memory_order_relaxed);
y.store(true, std::memory_order_relaxed);
}
void read_y_then_x()
{
while (!y.load(std::memory_order_relaxed));
if (x.load(std::memory_order_relaxed))
++z;
}
int main()
{
x = false;
y = false;
z = 0;
std::thread a(write_x_then_y);
std::thread b(read_y_then_x);
a.join();
b.join();
assert(z.load() != 0);
}
On x86 assert will never fire and the above code behaves as if the store to y and the load of y used release/acquire semantics.