Confusion about happens before relationship in concurrency

Clash Royale CLAN TAG#URR8PPPConfusion about happens before relationship in concurrency
Below is an example given in Concurrency in Action , and the author says the assert may fire, but I don't understand why.
assert
#include <atomic>
#include <thread>
#include <assert.h>
std::atomic<bool> x,y;
std::atomic<int> z;
void write_x_then_y()
{
x.store(true,std::memory_order_relaxed);
y.store(true,std::memory_order_relaxed);
}
void read_y_then_x()
{
while(!y.load(std::memory_order_relaxed));
if(x.load(std::memory_order_relaxed))
++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);
}
As far as I know, in each single thread, sequenced before also means happens before.
So in thread a the store to x happens before y, which means x should be modified before y and the result x.store should be visible before y is modified.
sequenced before
happens before
x
y
x
y
x.store
y
But in this example the author says that the store between x and y could be reordered, why? Does that violate the rule of sequenced before and happens before?
x
y
sequenced before
happens before
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
This might explain things about relaxed ordering en.cppreference.com/w/cpp/atomic/memory_order#Relaxed_ordering
– Sami Kuhmonen
2 mins ago