- Ta наблюдает x == true и y == false.
- Tb отмечает x == false и y == true.
В результате значение z может быть равно 0.
р>
Код: Выделить всё
std::atomic x(false),y(false);
std::atomic z(0);
void write_x() { // Ta
x.store(true, std::memory_order_release); // A
}
void write_y() { // Tb
y.store(true, std::memory_order_release); // B
}
void read_x_then_y() { // Tc
while(!x.load(std::memory_order_acquire)); // C
if(y.load(std::memory_order_acquire)) // D
++z;
}
void read_y_then_x() { // Td
while(!y.load(std::memory_order_acquire)); // E
if(x.load(std::memory_order_acquire)) // F
++z;
}
int main() {
std::thread a(write_x);
std::thread b(write_y);
std::thread c(read_x_then_y);
std::thread d(read_y_then_x);
a.join();
b.join();
c.join();
d.join();
assert(z.load() != 0);
}
Операторы A и B независимы друг от друга, поэтому они могут выполняться в любом порядке. В конкретном исполнении программы будет определенный порядок, например AB или BA. Например, предположим, что порядок равен AB:
- Когда поток Tc достигает D, x == true, но y все равно может быть ложным, поэтому ++z не будет выполнен.
- Когда поток Td достигнет F, y == true. Поскольку B выполняется после A, x уже должно быть истинным, поэтому будет выполнено ++z, в результате чего z > 0.
Изначально я подозревал, что результат std::atomic::store может не быть сразу виден другим потокам. Например, даже если A выполнился, Td все равно может увидеть x == false, предотвращая выполнение ++z. Однако, исследовав видимость атомарных операций, я обнаружил, что если x.store запускается до x.load, то x.load должен видеть результат x.store, как описано в этом вопросе о Memory_order_relaxed и видимости.
Так почему же Ta и Tb могут наблюдать разные состояния?
Подробнее здесь: https://stackoverflow.com/questions/792 ... ion-orders