The most common use of Boost.Atomic is to
realize custom thread synchronization protocols: The goal is to coordinate
accesses of threads to shared variables in order to avoid "conflicts".
The programmer must be aware of the fact that compilers, CPUs and the cache
hierarchies may generally reorder memory references at will. As a consequence
a program such as:

intx=0,inty=0;thread1:x=1;y=1;thread2if(y==1){assert(x==1);}

might indeed fail as there is no guarantee that the read of x
by thread2 "sees" the write by thread1.

Boost.Atomic uses a synchronisation concept
based on the happens-before relation to describe the guarantees
under which situations such as the above one cannot occur.

The remainder of this section will discuss happens-before
in a "hands-on" way instead of giving a fully formalized definition.
The reader is encouraged to additionally have a look at the discussion of the
correctness of a few of the examples
afterwards.

The "lockset-based intuition" would be to argue that A and B cannot
be executed concurrently as the code paths require a common lock to be held.

One can however also arrive at the same conclusion using happens-before:
Either thread1 or thread2 will succeed first at m.lock().
If this is be thread1, then as a consequence, thread2 cannot succeed at
m.lock() before thread1 has executed m.unlock(),
consequently A happens-before B in this case. By symmetry,
if thread2 succeeds at m.lock() first, we can conclude
B happens-before A.

Since this already exhausts all options, we can conclude that either A happens-before
B or B happens-before A must always hold. Obviously
cannot state which of the two relationships holds, but
either one is sufficient to conclude that A and B cannot conflict.

Compare the spinlock
implementation to see how the mutual exclusion concept can be mapped to
Boost.Atomic.

Ordering constraints are generally specified together with an access to an
atomic variable. It is however also possible to issue "fence" operations
in isolation, in this case the fence operates in conjunction with preceding
(for acquire, consume or seq_cst
operations) or succeeding (for release
or seq_cst) atomic operations.

The example from the previous section could also be written in the following
way:

The store operation by thread1 precedes the load
by thread2: In this case thread2 will read data[1]
and "A happens-before B" holds as all
of the criteria above are satisfied.

The load operation by thread2 precedes the store
by thread1: In this case thread2 will read data[0]
and "A happens-before B" does not
hold: thread2 does not read the value written by thread1 through a.

Here, the happens-before relationship helps ensure that
any accesses (presumable writes) to data[1] by thread1
happen before before the accesses (presumably reads) to data[1]
by thread2: Lacking this relationship, thread2 might see stale/inconsistent
data.

Note that in this example, the fact that operation B is computationally dependent
on the atomic variable, therefore the following program would be erroneous:

atomic<int>a(0);complex_data_structuredata[2];thread1:data[1]=...;/* A */a.store(1,memory_order_release);thread2:intindex=a.load(memory_order_consume);complex_data_structuretmp;if(index==0)tmp=data[0];elsetmp=data[1];