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
下面是否保证打印 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