假设我们有 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
上会出现数据争用。
通常,正确的代码应该是对原子 bool 变量使用relaxed
排序。
是否是因为对 isDataReady 的写入(事务)无法在读取之前完成?即使是这样,这真的是一个问题吗?
最佳答案
TL;DR
这种数据竞争很危险,您应该注意消除它。由于你的运气,它可能不会显现出来,但最终会引起头痛。
长一点
由于以下几个问题,此代码存在问题:
编译
Consumer
时,编译器不知道isDataReady
可以在后台发生变化,因此发出while(!isDataReady)
是完全合理的。 code> 无限循环或什么都没有(由于 forward progress guarantee ,正如评论中指出的那样)。如果对
bool
的写入和/或读取不是原子的(大多数平台上并非如此,但理论上是可能的),任何读取都可能导致获取垃圾数据。具有
std::memory_order_release
的内存栅栏可确保在其他线程使用std::memory_order_acquire
调用栅栏后,线程中发生的更改将可见(位于至少在简化方面)。因此,bool 变量的变化在其他线程中可能是不可见的。由于现代处理器的超标量架构,操作可能会在运行时由处理器重新排序。因此,从
Consumer
可见的Producer
中的内存写入顺序可能与代码中的顺序不同。
关于c++ - 原子线程栅栏 : Why is there a data race on this non atomic variable? 这有关系吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54110588/