<p>Sequential consistency provides a <em>single total order</em> of all sequentially consistent operations. So if you have a sequentially consistent store in thread A, and a sequentially consistent load in thread B, and the store is ordered before the load (in said single total order), then B observes the value stored by A. So basically sequential consistency guarantees that the store is &quot;immediately visible&quot; to other threads. A release store does <em>not</em> provide this guarantee.</p>
<p>As Peter Cordes pointed out correctly, the term &quot;immediately visible&quot; is rather imprecise. The &quot;visibility&quot; stems from the fact that all seq-cst operations are totally ordered, and all threads observe that order. Since the store and the load are totally ordered, the value of a store becomes visible before a subsequent load (in the single total order) is executed.</p>
<p>There exists no such total order between acquire/release operations in different threads, so there is not visibility guarantee. The operations are only ordered once an acquire-operations observes the value from a release-operation, but there is no guarantee <em>when</em> the value of the release-operation becomes visible to the thread performing the acquire-operation.</p>
<p>Let's consider what would happen if we were to use acquire/release in this example:</p>
<pre><code>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() {
    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);  // can actually happen!!
}
</code></pre>
<p>Since we have no guarantee about visibility, it could happen that thread <code>c</code> observes <code>x == true</code> and <code>y == false</code>, while at the same time thread <code>d</code> could observe <code>y == true</code> and <code>x == false</code>. So neither thread would increment <code>z</code> and the assertion would fire.</p>
<p>For more details about the C++ memory model I can recommend this paper which I have co-authored: <a href="https://arxiv.org/abs/1803.04432" rel="nofollow noreferrer">Memory Models for C/C++ Programmers</a></p>
C++ memory_order_acquire/release questions
<p>I recently learn about c++ six memory orders, I felt very confusing about <code>memory_order_acquire</code> and <code>memory_order_release</code>, here is an example from cpp:</p>
<pre class="lang-cpp prettyprint-override"><code>#include &lt;thread&gt;
#include &lt;atomic&gt;
#include &lt;cassert&gt;
 
std::atomic&lt;bool&gt; x = {false};
std::atomic&lt;bool&gt; y = {false};
std::atomic&lt;int&gt; z = {0};
 
void write_x() { x.store(true, std::memory_order_seq_cst); }
void write_y() { y.store(true, std::memory_order_seq_cst); }
 
void read_x_then_y() {
     while (!x.load(std::memory_order_seq_cst));

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

     if (x.load(std::memory_order_seq_cst))
        ++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);  // will never happen
}
</code></pre>
<p>In the cpp reference page, it says:</p>
<blockquote>
<p>This example demonstrates a situation where sequential ordering is necessary.</p>
<p>Any other ordering may trigger the assert because it would be possible
for the threads c and d to observe changes to the atomics x and y in
opposite order.</p>
</blockquote>
<p>So my question is why <strong>memory_order_acquire</strong> and <strong>memory_order_release</strong> can not be used here? And what semantics does memory_order_acquire and memory_order_release provide?</p>
<p>some references:
<a href="https://en.cppreference.com/w/cpp/atomic/memory_order" rel="nofollow noreferrer">https://en.cppreference.com/w/cpp/atomic/memory_order</a>
<a href="https://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync" rel="nofollow noreferrer">https://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync</a></p>