【发布时间】:2015-12-11 00:35:49
【问题描述】:
轻松排序
用 std::memory_order_relaxed 标记的原子操作不是同步操作;只有每个单独的原子对象的修改顺序在线程之间共享。不同对象之间相对于其他线程没有顺序;可以看到操作乱序。
示例 - 轻松排序
#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
}
线程 t1 和线程 t2 之间没有排序限制。因此,t2可以先看到B做的store,然后A做的store;在这种情况下,main() 中的断言 F 将触发。
此问题的明显解决方案是使 B 中的商店具有std::memory_order_release,而 C 中的负载具有std::memory_order_acquire 以用于同步目的。 F 中的断言似乎永远不会触发。
问题
但是,由于 A 和 B 之间没有 happens-before 关系(我错了吗?),编译器不能/optimizer/CPU 重新组织函数 f1() 中的指令,使得 B 是 sequenced-before A?这将导致函数f2() 中的C 计算为true,但D 将是false;断言可以触发。
有什么东西可以阻止这个问题的出现吗?
【问题讨论】:
-
A和B在同一个线程中,并且A在B之前排序,所以A在B之前发生。
-
A 在 B 之前发生,但是从另一个线程中 B 的副作用可能在 A 的副作用之前可见。
-
我认为即使 A 在 B 之前排序,如果 A 没有将依赖项带入 B,则不存在先于关系。那么,它们在之前排序这一事实是否意味着存在先发生关系?
-
@bku_drytt 那么任何程序将如何工作?您如何使任何副作用可见?
标签: c++ multithreading c++11