...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
.
Same with atomic_ref<T>
.
compare_exchange_strong
/compare_exchange_weak
fail, and given
that in some cases other operations are built upon these, potentially all
operations become unreliable. Boost.Atomic
does support padding bits for floating point types on platforms where the
location of the padding bits is known at compile time.