std::memory_order_relaxed 和初始化

std::memory_order_relaxed and initialization

下面是否保证打印 1 后跟 2?

auto&& atomic = std::atomic<int>{0};
std::atomic<int>* pointer = nullptr;

// thread 1
auto&& value = std::atomic<int>{1};
pointer = &value;
atomic.store(1, std::memory_order_relaxed);
while (atomic.load(std::memory_order_relaxed) != 2) {}
cout << value.load(std::memory_order_relaxed) << endl;

// thread 2
while (atomic.load(std::memory_order_relaxed) != 1) {}
cout << pointer->load(std::memory_order_relaxed); << endl;
pointer->fetch_add(1, std::memory_order_relaxed);
atomic.store(2, std::memory_order_relaxed) {}

如果不是,这里可能的输出是什么?对于这种情况,标准对初始化和内存顺序有何规定?

如评论中所述,'relaxed' 排序的使用阻止了任何必要的线程间同步的发生,因此,对 pointer 的访问是未同步的(或未排序的)。
这意味着线程 2 可以取消引用 pointer 而它仍然具有值 nullptr.
此外,由于 pointer 是非原子类型(即常规指针),因此可能无法在线程之间以这种方式访问​​。 从技术上讲,你有一个数据竞争,这会导致未定义的行为。

一个解决方案是稍微加强内存排序。我认为在 atomic 上使用 acquire/release 排序应该足够了:

auto&& atomic = std::atomic<int>{0};
std::atomic<int>* pointer = nullptr;

// thread 1
auto&& value = std::atomic<int>{1};
pointer = &value;
atomic.store(1, std::memory_order_release);
while (atomic.load(std::memory_order_acquire) != 2) {}
cout << value.load(std::memory_order_relaxed) << endl;

// thread 2
while (atomic.load(std::memory_order_acquire) != 1) {}
cout << pointer->load(std::memory_order_relaxed); << endl;
pointer->fetch_add(1, std::memory_order_relaxed);
atomic.store(2, std::memory_order_release) {}

有了这个顺序,结果一定会打印出来

1
2