我一直在努力理解栅栏实际上是如何强制代码同步的。
例如,假设我有这个代码
bool x = false;
std::atomic<bool> y;
std::atomic<int> z;
void write_x_then_y()
{
x = true;
std::atomic_thread_fence(std::memory_order_release);
y.store(true, std::memory_order_relaxed);
}
void read_y_then_x()
{
while (!y.load(std::memory_order_relaxed));
std::atomic_thread_fence(std::memory_order_acquire);
if (x)
++z;
}
int main()
{
x = false;
y = false;
z = 0;
std::thread a(write_x_then_y);
std::thread b(read_y_then_x);
a.join();
b.join();
assert(z.load() != 0);
}
因为释放栅栏之后是原子存储操作,而获取栅栏之前是原子加载,所以一切都按预期同步,并且断言不会触发
但如果 y 不是这样的原子变量
bool x;
bool y;
std::atomic<int> z;
void write_x_then_y()
{
x = true;
std::atomic_thread_fence(std::memory_order_release);
y = true;
}
void read_y_then_x()
{
while (!y);
std::atomic_thread_fence(std::memory_order_acquire);
if (x)
++z;
}
然后,我听说,可能会有一场数据竞赛。但这是为什么呢?为什么释放栅栏后必须跟原子存储,而获取栅栏前必须有原子加载才能使代码正确同步?
如果有人可以提供数据竞争导致断言触发的执行场景,我也将不胜感激