Я изо всех сил пытался понять, как заборы на самом деле заставляют код синхронизироваться.
например, скажем, у меня есть этот код
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;
}
тогда, как я слышал, может начаться гонка данных. Но почему? Почему за блоками освобождения должно следовать атомарное хранилище, а за блоками получения должна предшествовать атомарная загрузка, чтобы код правильно синхронизировался?
Я также был бы признателен, если бы кто-нибудь мог предоставить сценарий выполнения, в котором гонка данных вызывает срабатывание утверждения.