Adquirir / liberar semántica con 4 hilos

Actualmente estoy leyendo C ++ Concurrency in Action de Anthony Williams. Uno de sus listados muestra este código, y afirma que la afirmación de quez != 0 puede disparar

#include <atomic>
#include <thread>
#include <assert.h>

std::atomic<bool> x,y;
std::atomic<int> z;

void write_x()
{
    x.store(true,std::memory_order_release);
}

void write_y()
{
    y.store(true,std::memory_order_release);
}

void read_x_then_y()
{
    while(!x.load(std::memory_order_acquire));
    if(y.load(std::memory_order_acquire))
        ++z;
}

void read_y_then_x()
{
    while(!y.load(std::memory_order_acquire));
    if(x.load(std::memory_order_acquire))
        ++z;
}

int main()
{
    x=false;
    y=false;
    z=0;
    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);
}

Entonces, las diferentes rutas de ejecución, en las que puedo pensar es esta:

1)

Thread a (x is now true)
Thread c (fails to increment z)
Thread b (y is now true)
Thread d (increments z) assertion cannot fire

2)

Thread b (y is now true)
Thread d (fails to increment z)
Thread a (x is now true)
Thread c (increments z) assertion cannot fire

3)

Thread a (x is true)
Thread b (y is true)
Thread c (z is incremented) assertion cannot fire
Thread d (z is incremented)

¿Podría alguien explicarme cómo esta afirmación puede disparar?

Él muestra este pequeño gráfico:

¿No debería la tienday También sincronizar con la carga enread_x_then_yy la tienda ax sincronizar con la carga enread_y_then_x? Estoy muy confundido.

EDITAR:

Gracias por sus respuestas, entiendo cómo funcionan los atómicos y cómo usar Adquirir / Liberar. Simplemente no entiendo este ejemplo específico. Estaba tratando de averiguar SI la afirmación se dispara, entonces, ¿qué hizo cada hilo? ¿Y por qué la afirmación nunca se activa si usamos consistencia secuencial?

Por cierto, estoy razonando sobre esto es que sithread a (write_x) almacena enx entonces todo el trabajo que ha hecho hasta ahora se sincroniza con cualquier otro hilo que leax con adquirir pedidos. Una vezread_x_then_y ve esto, se escapa del ciclo y leey. Ahora, pueden pasar 2 cosas. En una opción, elwrite_y ha escrito ay, lo que significa que esta versión se sincronizará con la instrucción if (carga) que significaz se incrementa y la aserción no puede disparar. La otra opción es siwrite_y aún no se ha ejecutado, lo que significa que si la condición falla y z no se incrementa, en este escenario, solox es verdad yy Sigue siendo falso. Una vez que write_y se ejecuta, read_y_then_x sale de su ciclo, sin embargo, ambosx yy son verdaderas yz se incrementa y la afirmación no se dispara. No se me ocurre ninguna orden de "ejecución" o memoria dondez nunca se incrementa. ¿Alguien puede explicar dónde está defectuoso mi razonamiento?

Además, sé que la lectura del bucle siempre estará antes de la instrucción if, porque la adquisición evita este reordenamiento.

Respuestas a la pregunta(2)

Su respuesta a la pregunta