考虑一下我在http://preshing.com/20120913/acquire-and-release-semantics/找到的以下代码(但我确信我经常在其他地方看到它)
公共代码:
int A = 0;
std::atomic<int> Ready(0);
线程1执行的代码:
A = 42
Ready.store(1, std::memory_order_release);
线程2执行的代码:
int r1 = Ready.load(std::memory_order_acquire);
int r2 = A;
然后可以说,如果 r1 == 1
那么r2
将始终为42并且没有数据竞争。
我的第一个问题是:代码是否包含数据竞争?我的意思是r1 == 0
。例如,线程1可以在商店中途被抢占到A,然后线程2可以执行。
我认为线程2的代码应该重写为:
int r1 = Ready.load(std::memory_order_acquire);
int r2 = 0;
if( r1 == 1 ) {
r2 = A;
}
避免潜在的数据竞争。
这是真的吗?
答案 0 :(得分:1)
是的,您的解释是正确的:由于无条件阅读A
,该程序包含数据竞赛。该程序被简化为一个最小的例子,用于演示博客获取 - 发布的工作方式:作者仅讨论了内存排序如何强制“读者”线程必须从{{1}读取42如果它从A
读取1
。他没有谈论替代方案,因为它不是绅士。
在实际程序中,“reader”线程可能会在Ready
上循环等待以获得所需的语义:
Ready
或者在示例中使用条件:
int A = 0;
std::atomic<int> Ready(0);
void write_thread() {
A = 42;
Ready.store(1, std::memory_order_release);
}
void read_thread() {
while (!Ready.load(std::memory_order_acquire))
;
int r2 = A;
assert(r2 == 42);
}