...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
The library contains header-only and compiled parts. The library is header-only for lock-free cases but requires a separate binary to implement the lock-based emulation. Users are able to detect whether linking to the compiled part is required by checking the feature macros.
The following macros affect library behavior:
Macro |
Description |
---|---|
|
Affects 32-bit x86 Oracle Studio builds. When defined, the library
assumes the target CPU does not support |
|
Affects 64-bit x86 MSVC and Oracle Studio builds. When defined,
the library assumes the target CPU does not support |
|
Affects 32-bit x86 Oracle Studio builds. When defined, the library
assumes the target CPU does not support |
|
When defined, support for floating point operations is disabled. Floating point types shall be treated similar to trivially copyable structs and no capability macros will be defined. |
|
When defined, all operations are implemented with locks. This is mostly used for testing and should not be used in real world projects. |
|
Control library linking. If defined, the library assumes dynamic linking, otherwise static. The latter macro affects all Boost libraries, not just Boost.Atomic. |
|
Control library auto-linking on Windows. When defined, disables auto-linking. The latter macro affects all Boost libraries, not just Boost.Atomic. |
Besides macros, it is important to specify the correct compiler options for the target CPU. With GCC and compatible compilers this affects whether particular atomic operations are lock-free or not.
Boost building process is described in the Getting Started guide. For example, you can build Boost.Atomic with the following command line:
bjam --with-atomic variant=release instruction-set=core2 stage
#include <boost/memory_order.hpp>
The enumeration boost::memory_order
defines the following
values to represent memory ordering constraints:
Constant |
Description |
---|---|
|
No ordering constraint. Informally speaking, following operations
may be reordered before, preceding operations may be reordered
after the atomic operation. This constraint is suitable only when
either a) further operations do not depend on the outcome of the
atomic operation or b) ordering is enforced through stand-alone
|
|
Perform |
|
Perform |
|
Perform |
|
Perform both |
|
Enforce sequential consistency. Implies |
For compilers that support C++11 scoped enums, the library also defines scoped synonyms that are preferred in modern programs:
Pre-C++11 constant |
C++11 equivalent |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
See section happens-before for explanation of the various ordering constraints.
#include <boost/atomic/atomic_flag.hpp>
The boost::atomic_flag
type provides the most basic
set of atomic operations suitable for implementing mutually exclusive access
to thread-shared data. The flag can have one of the two possible states:
set and clear. The class implements the following operations:
Syntax |
Description |
---|---|
|
Initialize to the clear state. See the discussion below. |
|
Sets the atomic flag to the set state; returns |
|
Sets the atomic flag to the clear state |
order
always has memory_order_seq_cst
as default parameter.
Note that the default constructor atomic_flag()
is unlike std::atomic_flag
,
which leaves the default-constructed object uninitialized. This potentially
requires dynamic initialization during the program startup to perform the
object initialization, which makes it unsafe to create global boost::atomic_flag
objects that can be used before
entring main()
.
Some compilers though (especially those supporting C++11 constexpr
)
may be smart enough to perform flag initialization statically (which is,
in C++11 terms, a constant initialization).
This difference is deliberate and is done to support C++03 compilers. C++11
defines the ATOMIC_FLAG_INIT
macro which can be used to statically initialize std::atomic_flag
to a clear state like this:
std::atomic_flag flag = ATOMIC_FLAG_INIT; // constant initialization
This macro cannot be implemented in C++03 because for that atomic_flag
would have to be an aggregate
type, which it cannot be because it has to prohibit copying and consequently
define the default constructor. Thus the closest equivalent C++03 code using
Boost.Atomic would be:
boost::atomic_flag flag; // possibly, dynamic initialization in C++03; // constant initialization in C++11
The same code is also valid in C++11, so this code can be used universally.
However, for interface parity with std::atomic_flag
,
if possible, the library also defines the BOOST_ATOMIC_FLAG_INIT
macro, which is equivalent to ATOMIC_FLAG_INIT
:
boost::atomic_flag flag = BOOST_ATOMIC_FLAG_INIT; // constant initialization
This macro will only be implemented on a C++11 compiler. When this macro
is not available, the library defines BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT
.
#include <boost/atomic/atomic.hpp>
boost::atomic<T>
provides methods
for atomically accessing variables of a suitable type T
.
The type is suitable if it is trivially copyable (3.9/9
[basic.types]). Following are examples of the types compatible with this
requirement:
class
or struct
that has no non-trivial
copy or move constructors or assignment operators, has a trivial destructor,
and that is comparable via memcmp
.
Note that classes with virtual functions or virtual base classes do not satisfy
the requirements. Also be warned that structures with "padding"
between data members may compare non-equal via memcmp
even though all members are equal. This may also be the case with some floating
point types, which include padding bits themselves.
All atomic objects support the following operations and properties:
Syntax |
Description |
---|---|
|
Initialize to an unspecified value |
|
Initialize to |
|
Checks if the atomic object is lock-free; the returned value
is consistent with the |
|
Return current value |
|
Write new value to atomic variable |
|
Exchange current value with |
|
Compare current value with |
|
Compare current value with |
|
Compare current value with |
|
Compare current value with |
|
This static boolean constant indicates if any atomic object of this type is lock-free |
order
always has memory_order_seq_cst
as default parameter.
The compare_exchange_weak
/compare_exchange_strong
variants taking
four parameters differ from the three parameter variants in that they allow
a different memory ordering constraint to be specified in case the operation
fails.
In addition to these explicit operations, each atomic<T>
object also supports implicit store
and load
through the use of "assignment" and "conversion to T
"
operators. Avoid using these operators, as they do not allow to specify
a memory ordering constraint which always defaults to memory_order_seq_cst
.
In addition to the operations listed in the previous section, boost::atomic<I>
for integral types I
, except bool
, supports the following operations,
which correspond to std::atomic<I>
:
Syntax |
Description |
---|---|
|
Add |
|
Subtract |
|
Apply bit-wise "and" with |
|
Apply bit-wise "or" with |
|
Apply bit-wise "xor" with |
Additionally, as a Boost.Atomic extension, the following operations are also provided:
Syntax |
Description |
---|---|
|
Change the sign of the value stored in the variable, returning previous value |
|
Set the variable to the one's complement of the current value, returning previous value |
|
Change the sign of the value stored in the variable, returning the result |
|
Add |
|
Subtract |
|
Apply bit-wise "and" with |
|
Apply bit-wise "or" with |
|
Apply bit-wise "xor" with |
|
Set the variable to the one's complement of the current value, returning the result |
|
Change the sign of the value stored in the variable, returning nothing |
|
Add |
|
Subtract |
|
Apply bit-wise "and" with |
|
Apply bit-wise "or" with |
|
Apply bit-wise "xor" with |
|
Set the variable to the one's complement of the current value, returning nothing |
|
Change the sign of the value stored in the variable, returning
|
|
Add |
|
Subtract |
|
Apply bit-wise "and" with |
|
Apply bit-wise "or" with |
|
Apply bit-wise "xor" with |
|
Set the variable to the one's complement of the current value,
returning |
|
Set bit number |
|
Set bit number |
|
Change bit number |
Note | |
---|---|
In Boost.Atomic 1.66 the |
order
always has memory_order_seq_cst
as default parameter.
The opaque_op
and op_and_test
variants of the operations may result in a more efficient code on some
architectures because the original value of the atomic variable is not
preserved. In the bit_test_and_op
operations, the bit number n
starts from 0, which means the least significand bit, and must not exceed
std::numeric_limits<I>::digits - 1
.
In addition to these explicit operations, each boost::atomic<I>
object also supports implicit pre-/post- increment/decrement, as well as
the operators +=
, -=
, &=
,
|=
and ^=
.
Avoid using these operators, as they do not allow to specify a memory ordering
constraint which always defaults to memory_order_seq_cst
.
Note | |
---|---|
The support for floating point types is optional and can be disabled
by defining |
In addition to the operations applicable to all atomic objects, boost::atomic<F>
for floating point types F
supports
the following operations, which correspond to std::atomic<F>
:
Syntax |
Description |
---|---|
|
Add |
|
Subtract |
Additionally, as a Boost.Atomic extension, the following operations are also provided:
Syntax |
Description |
---|---|
|
Change the sign of the value stored in the variable, returning previous value |
|
Change the sign of the value stored in the variable, returning the result |
|
Add |
|
Subtract |
|
Change the sign of the value stored in the variable, returning nothing |
|
Add |
|
Subtract |
order
always has memory_order_seq_cst
as default parameter.
The opaque_op
variants of the operations
may result in a more efficient code on some architectures because the original
value of the atomic variable is not preserved.
In addition to these explicit operations, each boost::atomic<F>
object also supports operators +=
and -=
. Avoid using these
operators, as they do not allow to specify a memory ordering constraint
which always defaults to memory_order_seq_cst
.
When using atomic operations with floating point types, bear in mind that
Boost.Atomic always performs bitwise comparison
of the stored values. This means that operations like compare_exchange*
may fail if the stored value and comparand
have different binary representation, even if they would normally compare
equal. This is typically the case when either of the numbers is denormalized.
This also means that the behavior with regard to special floating point
values like NaN and signed zero is also different from normal C++.
Another source of the problem is padding bits that are added to some floating
point types for alignment. One widespread example of that is Intel x87
extended double format, which is typically stored as 80 bits of value padded
with 16 or 48 unused bits. These padding bits are often uninitialized and
contain garbage, which makes two equal numbers have different binary representation.
The library attempts to account for the known such cases, but in general
it is possible that some platforms are not covered. Note that the C++ standard
makes no guarantees about reliability of compare_exchange*
operations in the face of padding or trap
bits.
In addition to the operations applicable to all atomic objects, boost::atomic<P>
for pointer types P
(other than
pointers to void
, function or member pointers) support
the following operations, which correspond to std::atomic<P>
:
Syntax |
Description |
---|---|
|
Add |
|
Subtract |
Similarly to integers, the following Boost.Atomic extensions are also provided:
Syntax |
Description |
---|---|
|
Add |
|
Subtract |
|
Add |
|
Subtract |
|
Add |
|
Subtract |
order
always has memory_order_seq_cst
as default parameter.
In addition to these explicit operations, each boost::atomic<P>
object also supports implicit pre-/post- increment/decrement, as well as
the operators +=
, -=
. Avoid using these operators, as they
do not allow explicit specification of a memory ordering constraint which
always defaults to memory_order_seq_cst
.
For convenience, several shorthand typedefs of boost::atomic<T>
are provided:
typedef atomic< char > atomic_char; typedef atomic< unsigned char > atomic_uchar; typedef atomic< signed char > atomic_schar; typedef atomic< unsigned short > atomic_ushort; typedef atomic< short > atomic_short; typedef atomic< unsigned int > atomic_uint; typedef atomic< int > atomic_int; typedef atomic< unsigned long > atomic_ulong; typedef atomic< long > atomic_long; typedef atomic< unsigned long long > atomic_ullong; typedef atomic< long long > atomic_llong; typedef atomic< void* > atomic_address; typedef atomic< bool > atomic_bool; typedef atomic< wchar_t > atomic_wchar_t; typedef atomic< char16_t > atomic_char16_t; typedef atomic< char32_t > atomic_char32_t; typedef atomic< uint8_t > atomic_uint8_t; typedef atomic< int8_t > atomic_int8_t; typedef atomic< uint16_t > atomic_uint16_t; typedef atomic< int16_t > atomic_int16_t; typedef atomic< uint32_t > atomic_uint32_t; typedef atomic< int32_t > atomic_int32_t; typedef atomic< uint64_t > atomic_uint64_t; typedef atomic< int64_t > atomic_int64_t; typedef atomic< int_least8_t > atomic_int_least8_t; typedef atomic< uint_least8_t > atomic_uint_least8_t; typedef atomic< int_least16_t > atomic_int_least16_t; typedef atomic< uint_least16_t > atomic_uint_least16_t; typedef atomic< int_least32_t > atomic_int_least32_t; typedef atomic< uint_least32_t > atomic_uint_least32_t; typedef atomic< int_least64_t > atomic_int_least64_t; typedef atomic< uint_least64_t > atomic_uint_least64_t; typedef atomic< int_fast8_t > atomic_int_fast8_t; typedef atomic< uint_fast8_t > atomic_uint_fast8_t; typedef atomic< int_fast16_t > atomic_int_fast16_t; typedef atomic< uint_fast16_t > atomic_uint_fast16_t; typedef atomic< int_fast32_t > atomic_int_fast32_t; typedef atomic< uint_fast32_t > atomic_uint_fast32_t; typedef atomic< int_fast64_t > atomic_int_fast64_t; typedef atomic< uint_fast64_t > atomic_uint_fast64_t; typedef atomic< intmax_t > atomic_intmax_t; typedef atomic< uintmax_t > atomic_uintmax_t; typedef atomic< std::size_t > atomic_size_t; typedef atomic< std::ptrdiff_t > atomic_ptrdiff_t; typedef atomic< intptr_t > atomic_intptr_t; typedef atomic< uintptr_t > atomic_uintptr_t;
The typedefs are provided only if the corresponding type is available.
#include <boost/atomic/fences.hpp>
Syntax |
Description |
---|---|
|
Issue fence for coordination with other threads. |
|
Issue fence for coordination with signal handler (only in same thread). |
#include <boost/atomic/capabilities.hpp>
Boost.Atomic defines a number of macros
to allow compile-time detection whether an atomic data type is implemented
using "true" atomic operations, or whether an internal "lock"
is used to provide atomicity. The following macros will be defined to 0
if operations on the data type always require
a lock, to 1
if operations on
the data type may sometimes require a lock, and to 2
if they are always lock-free:
Macro |
Description |
---|---|
|
Indicate whether |
|
Indicate whether |
|
Indicate whether |
|
Indicate whether |
|
Indicate whether |
|
Indicate whether |
|
Indicate whether |
|
Indicate whether |
|
Indicate whether |
|
Indicate whether |
|
Indicate whether |
|
Indicate whether |
|
Indicate whether |
In addition to these standard macros, Boost.Atomic
also defines a number of extension macros, which can also be useful. Like
the standard ones, these macros are defined to values 0
,
1
and 2
to indicate whether the corresponding operations are lock-free or not.
Macro |
Description |
---|---|
|
Indicate whether |
|
Indicate whether |
|
Indicate whether |
|
Indicate whether |
|
Indicate whether |
|
Defined after including |
In the table above, intN_type
is a type that fits storage of contiguous N
bits, suitably aligned for atomic operations.
For floating-point types the following macros are similarly defined:
Macro |
Description |
---|---|
|
Indicate whether |
|
Indicate whether |
|
Indicate whether |
These macros are not defined when support for floating point types is disabled by user.