If a variable is declared with the std::atomic
template, such as std::atomic<int>
, is it guaranteed that access via the methods in std::atomic
will result in a consistent value (that is, one written by a write through the std::atomic
methods) regardless of ordering?
As far as I know, this equivalent to asking whether reads or writes can be "torn" - that is, written or real in multiple parts visible at the ISA level.
Atomic, from the Greek atom meaning indivisible, is synonymous with "no tearing". It means that the entire operation happens indivisbly. Everything you can do with a
std::atomic
type is always atomic (no tearing).C++14 draft N4140 section 29.3 Order and consistency is the first part of that chapter that gets down to details. One of the very first points is (1.4):
As far as technical language that lays out the atomicity requirement, every operation (like
.store()
,.load()
,.fetch_add()
) is defined with language like:And so on, using the word Atomically in every case it applies.
Instead of repeating themselves for
add
/+
,sub
/-
, and so for|
,&
, and^
, they have a key/op table that applies to this block:The only thing that's optional is ordering / synchronization with loads/stores in other threads (for atomicity without synchronization, use
memory_order_relaxed
).In fact, there's no way to "turn off" atomicity for loading a wide type where that's expensive (e.g. before a CAS on
atomic<pointer_and_ABAcounter>
which compiles tolock cmpxchg16b
on x86). I used a union hack in that answer to efficiently load the struct.And more importantly, the union is a workaround for gcc not optimizing
ptr_and_counter.ptr
to a load of just the pointer, which I think is safe at least on x86. Instead gcc insists on atomically loading the whole struct and then getting the pointer from the result. That's very bad when it's a 16-byte struct on x86-64, and fairly bad on x86-32. (See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80835)