フェンスが実際にコードの同期を強制する方法を理解するのに苦労しています。
たとえば、このコードがあるとします
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;
}
その場合、データ競合が発生する可能性があると聞きました。しかし、それはなぜですか?コードを適切に同期させるために、リリース フェンスの後にアトミック ストアが続き、取得フェンスの前にアトミック ロードが必要なのはなぜですか?
また、データ競合によってアサートが発生する実行シナリオを誰かが提供できれば幸いです