| Home | Libraries | People | FAQ | More

## Limitations

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:

- Aggregate initialization syntax is not supported: Since Boost.Atomic sometimes uses storage type that is different from the value type, the `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.
- Initializing constructor is not `constexpr` for some types: For value types other than integral types, `bool`, enums, floating point types and classes without padding, `atomic<>` initializing constructor needs to perform runtime conversion to the storage type and potentially clear padding bits. This limitation may be lifted for more categories of types in the future.
- Compilers may transform computation dependency to control dependency: Crucially, `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.
- Fence operations may enforce "too strong" compiler ordering: Semantically, `memory_order::acquire`/`memory_order::consume` and `memory_order::release` need to restrain reordering of memory operations only in one direction. Since in some compilers there is no way to express this constraint, these may act as "full compiler barriers". In corner cases this may result in a slightly less efficient code than a more capable compiler could generate. Boost.Atomic will use compiler intrinsics, if possible, to express the proper ordering constraints.
- Atomic operations may enforce "too strong" memory ordering in debug mode: On some compilers, disabling optimizations makes it impossible to provide memory ordering constraints as compile-time constants to the compiler intrinsics. This causes the compiler to silently ignore the provided constraints and choose the "strongest" memory order (`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.
- No interprocess fallback: using `atomic<T>` in shared memory only works correctly, if `atomic<T>::is_lock_free() == true`. Same with `atomic_ref<T>`. Advice: Use IPC atomic types for inter-process communication.
- Memory type requirements: Atomic objects cannot be placed in read-only memory, even if they are only read from. Here, read-only means that the memory region is mapped with read-only permissions by the OS, regardless of the `const`-qualification. Boost.Atomic may implement load operations using read-modify-write instructions on some targets, such as `CMPXCHG16B` on x86. The load operation does not change the object value, but the instruction issues a write to the memory location nonetheless, so the memory must be writable. There may be other hardware-specific restrictions on the memory types that can be used with atomic instructions. Also, the operating system may have additional restrictions on the memory type and the set of allowed operations on it to implement waiting and notifying operations correctly. Such requirements are system-specific. For example, on Mac OS IPC atomics cannot be placed in stack memory, as notifying operations may spuriously fail to wake up blocked threads. Boost.Atomic aims to support more atomic types and operations natively, even if it means not supporting some rarely useful corner cases. Advice: Non-IPC atomics can be safely used in regular read-write process-local memory (e.g. stack or obtained via `malloc` or `new`), and IPC atomics can be used in read-write process-shared memory (e.g. obtained via `shm_open`+ `mmap`). Any special memory types, such as mapped device memory or memory mapped with special caching strategies (i.e. other than write-back), are not guaranteed to work and are subject to system-specific restrictions.
- Signed integers must use two's complement representation: Boost.Atomic makes this requirement in order to implement conversions between signed and unsigned integers internally. C++11 requires all atomic arithmetic operations on integers to be well defined according to two's complement arithmetics, which means that Boost.Atomic has to operate on unsigned integers internally to avoid undefined behavior that results from signed integer overflows. Platforms with other signed integer representations are not supported. Note that C++20 makes two's complement representation of signed integers mandatory.
- Limited support for types with padding bits: There is no portable way to clear the padding bits of an object. Doing so requires support from the compiler, which is typically available in compilers supporting C++20. Without clearing the padding, `compare_exchange_strong`/`compare_exchange_weak` are not able to function as intended, as they will fail spuriously because of mismatching contents in the padding. Note that other operations may be implemented in terms of `compare_exchange_*` internally. If the compiler does not offer a way to clear padding bits, Boost.Atomic does support padding bits for floating point types on platforms where the location of the padding bits is known at compile time, but otherwise types with padding cannot be supported. Note that, as discussed in `atomic` description, unions with padding bits cannot be reliably supported even on compilers that do offer a way to clear the padding.