Memory ordering issues require two sides to manifest, since even the most extreme out-of-order architecture presents itself as in-order to a single thread.
Imagine that code was paired with code in another thread that did:
*b = newValue;
barrier();
*a = 1;
We put a barrier here to ensure the stores don't get reordered, since we must write out the new value in b before writing out the flag in a that tells the other code to use it.
Paired with this, my example above will work fine on an architecture with strong ordering, but will potentially get a bad value into y on archs with weak ordering. The reader may fetch the value in b first, getting the value before the reassignment. It may then fetch the value in a and see 1. This will cause it to use the old value loaded from *b, which is semantically incorrect in this case even though it's perfectly correct according to the architecture and the language spec.
Correct code here would need an acquire barrier on the load of a, paired with a release barrier on the store.