Boost logo

Boost Users :

Subject: [Boost-users] boost vs std atomic sequential consistency semantics
From: Isaac To (isaac.to_at_[hidden])
Date: 2015-04-15 02:42:57


I've asked the question in stack overflow, but no luck there. I hope I
will see some light here.

I'd like to write a C++ object where there are many logger threads logging
to a large global (non-atomic) ring buffer, with an occasional reader
thread which wants to read as much data in the buffer as possible. I ended
up having a global atomic counter where loggers get locations to write to,
and each logger increments the counter atomically before writing. The
reader tries to read the buffer and per-logger local (atomic) variable to
know whether particular buffer entries are busy being written by some
logger, so as to avoid using them.

So I have to do synchronization between a pure reader thread and many
writer threads. I sense that the problem can be solved without using locks,
and I can rely on "happens after" relation to determine whether my program
is correct.

I've tried relaxed atomic operation, but it won't work: atomic variable
stores are releases and loads are acquires, and the guarantee is that some
acquire (and its subsequent work) always "happens after" some release (and
its preceding work). That means there is no way for the reader thread
(doing no store at all) to guarantee that something "happens after" the
time it reads the buffer, which means I don't know whether some logger has
overwritten part of the buffer when the thread is reading it.

So I turned to sequential consistency. For me, "atomic" means Boost.Atomic,
which notion of sequential consistency has a "pattern" documented
<http://www.boost.org/doc/libs/1_57_0/doc/html/atomic/thread_coordination.html#atomic.thread_coordination.seq_cst>
:

The third pattern for coordinating threads via Boost.Atomic uses seq_cst
for coordination: If ...

   1. thread1 performs an operation A,
   2. thread1 subsequently performs any operation with seq_cst,
   3. thread1 subsequently performs an operation B,
   4. thread2 performs an operation C,
   5. thread2 subsequently performs any operation with seq_cst,
   6. thread2 subsequently performs an operation D,

then either "A happens-before D" or "C happens-before B" holds.

Note that the second and fifth lines say "any operation", without saying
whether it modify anything, or what it operates on. This provides the
guarantee that I wanted.

All is happy until I watch the talk of Herb Sutter titled "atomic<>
Weapons". What he implied is that seq_cst is just a acq_rel, with the
additional guarantee of consistent atomic stores ordering. The suggestion
that sequentially consistent atomic operations may be re-ordered with
non-atomic operations only adds to my mystery. I turned to the
cppreference.com <http://en.cppreference.com/w/cpp/atomic/memory_order>,
which have similar descriptions.

So my questions:

   1. Does C++11 and Boost Atomic implement the same memory model?
   2. If (1) is "yes", does it mean the "pattern" described by Boost is
   somehow implied by the C++11 memory model? How? Or does it mean the
   documentation of either Boost or C++11 in cppreference is wrong?
   3. If (1) is "yes", but (2) is "Boost documentation is incorrect", is
   there any way to achieve the effect I want, namely to have guarantee that
   (the work subsequent to) some atomic store happens after (the work
   preceding) some atomic load?
   4. If (1) is "no", is there any way to achieve the effect I want in
   C++11?



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net