假设我们有2个线程。一位生产者和一位消费者。我们拥有生产数据的生产者和使用该数据的消费者。但是,后卫不是原子的!
bool isDataReady = false;
int data = 0;
void Producer() {
data = 42;
std::atomic_thread_fence(std::memory_order_release);
isDataReady = true;
}
void Consumer() {
while(!isDataReady);
std::atomic_thread_fence(std::memory_order_acquire);
assert(data == 42);
}
我想知道为什么isDataReady
上发生了数据竞赛。
通常,正确的代码应该是对原子布尔变量使用relaxed
排序。
是因为对isDataReady的写入(事务)可能在读取之前未完成?即使是这样,这真的有问题吗?
答案 0 :(得分:4)
此数据竞赛非常危险,您应该注意消除它。它可能不会因您的运气而显现出来,但最终会引起头痛。
由于一些问题,此代码有问题:
尽管编译Consumer
的编译器不知道isDataReady
可以在后台更改,所以发出while(!isDataReady)
无限循环或什么也不发出(由于{{ 3}},正如评论中指出的那样。
如果对bool
的写入和/或读取不是原子的(在大多数平台上不是这种情况,但从理论上讲是可能的),则任何读取都会导致获取垃圾数据。
带有std::memory_order_release
的内存隔离栅确保在其他线程调用带有std::memory_order_acquire
的篱笆之后,线程中发生的更改将是可见的(至少是为了简化)。因此,布尔变量的更改可能在其他线程中不可见。
由于现代处理器的超标量体系结构,操作可能会在运行时由处理器重新排序。因此,从Producer
可见的Consumer
中的内存写入顺序可能与代码中的写入顺序不同。