...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
While Boost.Atomic strives to implement the atomic operations from C++11 and later as faithfully as possible, there are a few limitations that cannot be lifted without compiler support:
atomic<>
template needs an initialization
constructor that performs the necessary conversion. This makes atomic<>
a non-aggregate type and prohibits aggregate initialization syntax (atomic<int> a = {10}
).
Boost.Atomic does support direct and unified
initialization syntax though. Advice:
Always use direct initialization (atomic<int> a(10)
)
or unified initialization (atomic<int> a{10}
)
syntax.
constexpr
for some types: For value types other than integral types and
bool
, atomic<>
initializing constructor needs
to perform runtime conversion to the storage type. This limitation may
be lifted for more categories of types in the future.
atomic<>
,
the default constructor must also be defined. In C++03 the constructor
cannot be defined as defaulted and therefore it is not trivial. In C++11
the constructor is defaulted (and trivial, if the default constructor of
the value type is). In any case, the default constructor of atomic<>
performs default initialization of the atomic value, as required in C++11.
Advice: In C++03, do not use Boost.Atomic in contexts where trivial default constructor
is important (e.g. as a global variable which is required to be statically
initialized).
memory_order_consume
only affects computationally-dependent operations, but in general there
is nothing preventing a compiler from transforming a computation dependency
into a control dependency. A fully compliant C++11 compiler would be forbidden
from such a transformation, but in practice most if not all compilers have
chosen to promote memory_order_consume
to memory_order_acquire
instead (see this
gcc bug for example). In the current implementation Boost.Atomic
follows that trend, but this may change in the future. Advice:
In general, avoid memory_order_consume
and use memory_order_acquire
instead. Use memory_order_consume
only in conjunction with pointer values, and only if you can ensure that
the compiler cannot speculate and transform these into control dependencies.
memory_order_acquire
/memory_order_consume
and memory_order_release
need to restrain
reordering of memory operations only in one direction. Since in C++03 there
is no way to express this constraint to the compiler, these act as "full
compiler barriers" in C++03 implementation. In corner cases this may
result in a slightly less efficient code than a C++11 compiler could generate.
Boost.Atomic will use compiler intrinsics,
if possible, to express the proper ordering constraints.
memory_order_seq_cst
)
to generate code. Not only this reduces performance, this may hide bugs
in the user's code (e.g. if the user used a wrong memory order constraint,
which caused a data race). Advice: Always
test your code with optimizations enabled.
atomic<T>
in shared memory only works correctly, if atomic<T>::is_lock_free() == true
.