std::atomic<int> cnt = {2};
thread 1:
doFoo();
if (cnt.fetch_sub(1, std::memory_order_relaxed) == 1) {
doBazz();
}
thread 2:
doBar();
if (cnt.fetch_sub(1, std::memory_order_relaxed) == 1) {
doBazz();
}
我们可以保证doFoo()
和doBar()
始终在doBazz()
之前发生吗?
答案 0 :(得分:-1)
您所显示的代码中根本没有内存订购,因此保证不成立。但是,通过fetch_sub
成为release sequence的一部分,您可以在适当的位置使用宽松的排序并使其有效:
std::atomic<int> cnt{0};
cnt.store(2, std::memory_order_release); // initiate release sequence (RS)
//thread 1:
doFoo();
if (cnt.fetch_sub(1, std::memory_order_relaxed) == 1) { // continue RS
std::atomic_thread_fence(std::memory_order_acquire); // synchronizes with RS
doBazz();
}
//thread 2:
doBar();
if (cnt.fetch_sub(1, std::memory_order_relaxed) == 1) { // continue RS
std::atomic_thread_fence(std::memory_order_acquire); // synchronizes with RS
doBazz();
}
或
void doBazz();
std::atomic<int> cnt{0};
cnt.store(2, std::memory_order_release); // initiate release sequence (RS)
//thread 1:
doFoo();
if (cnt.fetch_sub(1, std::memory_order_relaxed) == 1) { // continue RS
doBazz();
}
//thread 2:
doBar();
if (cnt.fetch_sub(1, std::memory_order_relaxed) == 1) { // continue RS
doBazz();
}
void doBazz() {
std::atomic_thread_fence(std::memory_order_acquire); // synchronizes with RS
// ...
}
这些保证doFoo()
和doBar()
始终在doBazz()
之前发生。
答案 1 :(得分:-1)
http://en.cppreference.com/w/cpp/atomic/memory_order
即使使用宽松的内存模型,也不允许超薄空间值循环依赖于它们自己的计算,例如,x和y最初为零,
// Thread 1:
r1 = x.load(memory_order_relaxed);
if (r1 == 42) y.store(r1, memory_order_relaxed);
// Thread 2:
r2 = y.load(memory_order_relaxed);
if (r2 == 42) x.store(42, memory_order_relaxed);
不允许产生r1 == r2 == 42,因为42到y的存储仅在存储到x存储42时才可能,这通常依赖于存储到y存储42.注意直到C ++ 14,这在技术上是规范允许的,但不建议用于实现者。
即使使用memory_order_relaxed,仍然有一些不允许的执行顺序。在我看来
cnt.fetch_sub(1, std::memory_order_relaxed) == 2
应该在
之前发生cnt.fetch_sub(1, std::memory_order_relaxed) == 1
正确?因此doFoo()和doBar()都应该在doBazz()之前发生。