1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279 |
- [/
- / Copyright (c) 2009 Helge Bahmann
- / Copyright (c) 2014, 2017, 2018 Andrey Semashev
- /
- / Distributed under the Boost Software License, Version 1.0. (See accompanying
- / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- /]
- [library Boost.Atomic
- [quickbook 1.4]
- [authors [Bahmann, Helge][Semashev, Andrey]]
- [copyright 2011 Helge Bahmann]
- [copyright 2012 Tim Blechmann]
- [copyright 2013, 2017, 2018 Andrey Semashev]
- [id atomic]
- [dirname atomic]
- [purpose Atomic operations]
- [license
- Distributed under the Boost Software License, Version 1.0.
- (See accompanying file LICENSE_1_0.txt or copy at
- [@http://www.boost.org/LICENSE_1_0.txt])
- ]
- ]
- [section:introduction Introduction]
- [section:introduction_presenting Presenting Boost.Atomic]
- [*Boost.Atomic] is a library that provides [^atomic]
- data types and operations on these data types, as well as memory
- ordering constraints required for coordinating multiple threads through
- atomic variables. It implements the interface as defined by the C++11
- standard, but makes this feature available for platforms lacking
- system/compiler support for this particular C++11 feature.
- Users of this library should already be familiar with concurrency
- in general, as well as elementary concepts such as "mutual exclusion".
- The implementation makes use of processor-specific instructions where
- possible (via inline assembler, platform libraries or compiler
- intrinsics), and falls back to "emulating" atomic operations through
- locking.
- [endsect]
- [section:introduction_purpose Purpose]
- Operations on "ordinary" variables are not guaranteed to be atomic.
- This means that with [^int n=0] initially, two threads concurrently
- executing
- [c++]
- void function()
- {
- n ++;
- }
- might result in [^n==1] instead of 2: Each thread will read the
- old value into a processor register, increment it and write the result
- back. Both threads may therefore write [^1], unaware that the other thread
- is doing likewise.
- Declaring [^atomic<int> n=0] instead, the same operation on
- this variable will always result in [^n==2] as each operation on this
- variable is ['atomic]: This means that each operation behaves as if it
- were strictly sequentialized with respect to the other.
- Atomic variables are useful for two purposes:
- * as a means for coordinating multiple threads via custom
- coordination protocols
- * as faster alternatives to "locked" access to simple variables
- Take a look at the [link atomic.usage_examples examples] section
- for common patterns.
- [endsect]
- [endsect]
- [section:thread_coordination Thread coordination using Boost.Atomic]
- The most common use of [*Boost.Atomic] is to realize custom
- thread synchronization protocols: The goal is to coordinate
- accesses of threads to shared variables in order to avoid
- "conflicts". The
- programmer must be aware of the fact that
- compilers, CPUs and the cache
- hierarchies may generally reorder memory references at will.
- As a consequence a program such as:
- [c++]
- int x = 0, int y = 0;
- thread1:
- x = 1;
- y = 1;
- thread2
- if (y == 1) {
- assert(x == 1);
- }
- might indeed fail as there is no guarantee that the read of `x`
- by thread2 "sees" the write by thread1.
- [*Boost.Atomic] uses a synchronisation concept based on the
- ['happens-before] relation to describe the guarantees under
- which situations such as the above one cannot occur.
- The remainder of this section will discuss ['happens-before] in
- a "hands-on" way instead of giving a fully formalized definition.
- The reader is encouraged to additionally have a
- look at the discussion of the correctness of a few of the
- [link atomic.usage_examples examples] afterwards.
- [section:mutex Enforcing ['happens-before] through mutual exclusion]
- As an introductory example to understand how arguing using
- ['happens-before] works, consider two threads synchronizing
- using a common mutex:
- [c++]
- mutex m;
- thread1:
- m.lock();
- ... /* A */
- m.unlock();
- thread2:
- m.lock();
- ... /* B */
- m.unlock();
- The "lockset-based intuition" would be to argue that A and B
- cannot be executed concurrently as the code paths require a
- common lock to be held.
- One can however also arrive at the same conclusion using
- ['happens-before]: Either thread1 or thread2 will succeed first
- at [^m.lock()]. If this is be thread1, then as a consequence,
- thread2 cannot succeed at [^m.lock()] before thread1 has executed
- [^m.unlock()], consequently A ['happens-before] B in this case.
- By symmetry, if thread2 succeeds at [^m.lock()] first, we can
- conclude B ['happens-before] A.
- Since this already exhausts all options, we can conclude that
- either A ['happens-before] B or B ['happens-before] A must
- always hold. Obviously cannot state ['which] of the two relationships
- holds, but either one is sufficient to conclude that A and B
- cannot conflict.
- Compare the [link boost_atomic.usage_examples.example_spinlock spinlock]
- implementation to see how the mutual exclusion concept can be
- mapped to [*Boost.Atomic].
- [endsect]
- [section:release_acquire ['happens-before] through [^release] and [^acquire]]
- The most basic pattern for coordinating threads via [*Boost.Atomic]
- uses [^release] and [^acquire] on an atomic variable for coordination: If ...
- * ... thread1 performs an operation A,
- * ... thread1 subsequently writes (or atomically
- modifies) an atomic variable with [^release] semantic,
- * ... thread2 reads (or atomically reads-and-modifies)
- the value this value from the same atomic variable with
- [^acquire] semantic and
- * ... thread2 subsequently performs an operation B,
- ... then A ['happens-before] B.
- Consider the following example
- [c++]
- atomic<int> a(0);
- thread1:
- ... /* A */
- a.fetch_add(1, memory_order_release);
- thread2:
- int tmp = a.load(memory_order_acquire);
- if (tmp == 1) {
- ... /* B */
- } else {
- ... /* C */
- }
- In this example, two avenues for execution are possible:
- * The [^store] operation by thread1 precedes the [^load] by thread2:
- In this case thread2 will execute B and "A ['happens-before] B"
- holds as all of the criteria above are satisfied.
- * The [^load] operation by thread2 precedes the [^store] by thread1:
- In this case, thread2 will execute C, but "A ['happens-before] C"
- does ['not] hold: thread2 does not read the value written by
- thread1 through [^a].
- Therefore, A and B cannot conflict, but A and C ['can] conflict.
- [endsect]
- [section:fences Fences]
- Ordering constraints are generally specified together with an access to
- an atomic variable. It is however also possible to issue "fence"
- operations in isolation, in this case the fence operates in
- conjunction with preceding (for `acquire`, `consume` or `seq_cst`
- operations) or succeeding (for `release` or `seq_cst`) atomic
- operations.
- The example from the previous section could also be written in
- the following way:
- [c++]
- atomic<int> a(0);
- thread1:
- ... /* A */
- atomic_thread_fence(memory_order_release);
- a.fetch_add(1, memory_order_relaxed);
- thread2:
- int tmp = a.load(memory_order_relaxed);
- if (tmp == 1) {
- atomic_thread_fence(memory_order_acquire);
- ... /* B */
- } else {
- ... /* C */
- }
- This provides the same ordering guarantees as previously, but
- elides a (possibly expensive) memory ordering operation in
- the case C is executed.
- [endsect]
- [section:release_consume ['happens-before] through [^release] and [^consume]]
- The second pattern for coordinating threads via [*Boost.Atomic]
- uses [^release] and [^consume] on an atomic variable for coordination: If ...
- * ... thread1 performs an operation A,
- * ... thread1 subsequently writes (or atomically modifies) an
- atomic variable with [^release] semantic,
- * ... thread2 reads (or atomically reads-and-modifies)
- the value this value from the same atomic variable with [^consume] semantic and
- * ... thread2 subsequently performs an operation B that is ['computationally
- dependent on the value of the atomic variable],
- ... then A ['happens-before] B.
- Consider the following example
- [c++]
- atomic<int> a(0);
- complex_data_structure data[2];
- thread1:
- data[1] = ...; /* A */
- a.store(1, memory_order_release);
- thread2:
- int index = a.load(memory_order_consume);
- complex_data_structure tmp = data[index]; /* B */
- In this example, two avenues for execution are possible:
- * The [^store] operation by thread1 precedes the [^load] by thread2:
- In this case thread2 will read [^data\[1\]] and "A ['happens-before] B"
- holds as all of the criteria above are satisfied.
- * The [^load] operation by thread2 precedes the [^store] by thread1:
- In this case thread2 will read [^data\[0\]] and "A ['happens-before] B"
- does ['not] hold: thread2 does not read the value written by
- thread1 through [^a].
- Here, the ['happens-before] relationship helps ensure that any
- accesses (presumable writes) to [^data\[1\]] by thread1 happen before
- before the accesses (presumably reads) to [^data\[1\]] by thread2:
- Lacking this relationship, thread2 might see stale/inconsistent
- data.
- Note that in this example, the fact that operation B is computationally
- dependent on the atomic variable, therefore the following program would
- be erroneous:
- [c++]
- atomic<int> a(0);
- complex_data_structure data[2];
- thread1:
- data[1] = ...; /* A */
- a.store(1, memory_order_release);
- thread2:
- int index = a.load(memory_order_consume);
- complex_data_structure tmp;
- if (index == 0)
- tmp = data[0];
- else
- tmp = data[1];
- [^consume] is most commonly (and most safely! see
- [link atomic.limitations limitations]) used with
- pointers, compare for example the
- [link boost_atomic.usage_examples.singleton singleton with double-checked locking].
- [endsect]
- [section:seq_cst Sequential consistency]
- The third pattern for coordinating threads via [*Boost.Atomic]
- uses [^seq_cst] for coordination: If ...
- * ... thread1 performs an operation A,
- * ... thread1 subsequently performs any operation with [^seq_cst],
- * ... thread1 subsequently performs an operation B,
- * ... thread2 performs an operation C,
- * ... thread2 subsequently performs any operation with [^seq_cst],
- * ... thread2 subsequently performs an operation D,
- then either "A ['happens-before] D" or "C ['happens-before] B" holds.
- In this case it does not matter whether thread1 and thread2 operate
- on the same or different atomic variables, or use a "stand-alone"
- [^atomic_thread_fence] operation.
- [endsect]
- [endsect]
- [section:interface Programming interfaces]
- [section:configuration Configuration and building]
- 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
- [link atomic.interface.feature_macros feature macros].
- The following macros affect library behavior:
- [table
- [[Macro] [Description]]
- [[`BOOST_ATOMIC_NO_CMPXCHG8B`] [Affects 32-bit x86 Oracle Studio builds. When defined,
- the library assumes the target CPU does not support `cmpxchg8b` instruction used
- to support 64-bit atomic operations. This is the case with very old CPUs (pre-Pentium).
- The library does not perform runtime detection of this instruction, so running the code
- that uses 64-bit atomics on such CPUs will result in crashes, unless this macro is defined.
- Note that the macro does not affect MSVC, GCC and compatible compilers because the library infers
- this information from the compiler-defined macros.]]
- [[`BOOST_ATOMIC_NO_CMPXCHG16B`] [Affects 64-bit x86 MSVC and Oracle Studio builds. When defined,
- the library assumes the target CPU does not support `cmpxchg16b` instruction used
- to support 128-bit atomic operations. This is the case with some early 64-bit AMD CPUs,
- all Intel CPUs and current AMD CPUs support this instruction. The library does not
- perform runtime detection of this instruction, so running the code that uses 128-bit
- atomics on such CPUs will result in crashes, unless this macro is defined. Note that
- the macro does not affect GCC and compatible compilers because the library infers
- this information from the compiler-defined macros.]]
- [[`BOOST_ATOMIC_NO_MFENCE`] [Affects 32-bit x86 Oracle Studio builds. When defined,
- the library assumes the target CPU does not support `mfence` instruction used
- to implement thread fences. This instruction was added with SSE2 instruction set extension,
- which was available in CPUs since Intel Pentium 4. The library does not perform runtime detection
- of this instruction, so running the library code on older CPUs will result in crashes, unless
- this macro is defined. Note that the macro does not affect MSVC, GCC and compatible compilers
- because the library infers this information from the compiler-defined macros.]]
- [[`BOOST_ATOMIC_NO_FLOATING_POINT`] [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.]]
- [[`BOOST_ATOMIC_FORCE_FALLBACK`] [When defined, all operations are implemented with locks.
- This is mostly used for testing and should not be used in real world projects.]]
- [[`BOOST_ATOMIC_DYN_LINK` and `BOOST_ALL_DYN_LINK`] [Control library linking. If defined,
- the library assumes dynamic linking, otherwise static. The latter macro affects all Boost
- libraries, not just [*Boost.Atomic].]]
- [[`BOOST_ATOMIC_NO_LIB` and `BOOST_ALL_NO_LIB`] [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 [@http://www.boost.org/doc/libs/release/more/getting_started/ Getting Started guide].
- For example, you can build [*Boost.Atomic] with the following command line:
- [pre
- bjam --with-atomic variant=release instruction-set=core2 stage
- ]
- [endsect]
- [section:interface_memory_order Memory order]
- #include <boost/memory_order.hpp>
- The enumeration [^boost::memory_order] defines the following
- values to represent memory ordering constraints:
- [table
- [[Constant] [Description]]
- [[`memory_order_relaxed`] [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 `atomic_thread_fence` operations. The operation on
- the atomic value itself is still atomic though.
- ]]
- [[`memory_order_release`] [
- Perform `release` operation. Informally speaking,
- prevents all preceding memory operations to be reordered
- past this point.
- ]]
- [[`memory_order_acquire`] [
- Perform `acquire` operation. Informally speaking,
- prevents succeeding memory operations to be reordered
- before this point.
- ]]
- [[`memory_order_consume`] [
- Perform `consume` operation. More relaxed (and
- on some architectures more efficient) than `memory_order_acquire`
- as it only affects succeeding operations that are
- computationally-dependent on the value retrieved from
- an atomic variable.
- ]]
- [[`memory_order_acq_rel`] [Perform both `release` and `acquire` operation]]
- [[`memory_order_seq_cst`] [
- Enforce sequential consistency. Implies `memory_order_acq_rel`, but
- additionally enforces total order for all operations such qualified.
- ]]
- ]
- For compilers that support C++11 scoped enums, the library also defines scoped synonyms
- that are preferred in modern programs:
- [table
- [[Pre-C++11 constant] [C++11 equivalent]]
- [[`memory_order_relaxed`] [`memory_order::relaxed`]]
- [[`memory_order_release`] [`memory_order::release`]]
- [[`memory_order_acquire`] [`memory_order::acquire`]]
- [[`memory_order_consume`] [`memory_order::consume`]]
- [[`memory_order_acq_rel`] [`memory_order::acq_rel`]]
- [[`memory_order_seq_cst`] [`memory_order::seq_cst`]]
- ]
- See section [link atomic.thread_coordination ['happens-before]] for explanation
- of the various ordering constraints.
- [endsect]
- [section:interface_atomic_flag Atomic flags]
- #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:
- [table
- [[Syntax] [Description]]
- [
- [`atomic_flag()`]
- [Initialize to the clear state. See the discussion below.]
- ]
- [
- [`bool test_and_set(memory_order order)`]
- [Sets the atomic flag to the set state; returns `true` if the flag had been set prior to the operation]
- ]
- [
- [`void clear(memory_order order)`]
- [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`.
- [endsect]
- [section:interface_atomic_object Atomic objects]
- #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:
- * a scalar type (e.g. integer, boolean, enum or pointer type)
- * a [^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.
- [section:interface_atomic_generic [^boost::atomic<['T]>] template class]
- All atomic objects support the following operations and properties:
- [table
- [[Syntax] [Description]]
- [
- [`atomic()`]
- [Initialize to an unspecified value]
- ]
- [
- [`atomic(T initial_value)`]
- [Initialize to [^initial_value]]
- ]
- [
- [`bool is_lock_free()`]
- [Checks if the atomic object is lock-free; the returned value is consistent with the `is_always_lock_free` static constant, see below]
- ]
- [
- [`T load(memory_order order)`]
- [Return current value]
- ]
- [
- [`void store(T value, memory_order order)`]
- [Write new value to atomic variable]
- ]
- [
- [`T exchange(T new_value, memory_order order)`]
- [Exchange current value with `new_value`, returning current value]
- ]
- [
- [`bool compare_exchange_weak(T & expected, T desired, memory_order order)`]
- [Compare current value with `expected`, change it to `desired` if matches.
- Returns `true` if an exchange has been performed, and always writes the
- previous value back in `expected`. May fail spuriously, so must generally be
- retried in a loop.]
- ]
- [
- [`bool compare_exchange_weak(T & expected, T desired, memory_order success_order, memory_order failure_order)`]
- [Compare current value with `expected`, change it to `desired` if matches.
- Returns `true` if an exchange has been performed, and always writes the
- previous value back in `expected`. May fail spuriously, so must generally be
- retried in a loop.]
- ]
- [
- [`bool compare_exchange_strong(T & expected, T desired, memory_order order)`]
- [Compare current value with `expected`, change it to `desired` if matches.
- Returns `true` if an exchange has been performed, and always writes the
- previous value back in `expected`.]
- ]
- [
- [`bool compare_exchange_strong(T & expected, T desired, memory_order success_order, memory_order failure_order))`]
- [Compare current value with `expected`, change it to `desired` if matches.
- Returns `true` if an exchange has been performed, and always writes the
- previous value back in `expected`.]
- ]
- [
- [`static bool is_always_lock_free`]
- [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`.
- [endsect]
- [section:interface_atomic_integral [^boost::atomic<['integral]>] template class]
- 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]>]:
- [table
- [[Syntax] [Description]]
- [
- [`I fetch_add(I v, memory_order order)`]
- [Add `v` to variable, returning previous value]
- ]
- [
- [`I fetch_sub(I v, memory_order order)`]
- [Subtract `v` from variable, returning previous value]
- ]
- [
- [`I fetch_and(I v, memory_order order)`]
- [Apply bit-wise "and" with `v` to variable, returning previous value]
- ]
- [
- [`I fetch_or(I v, memory_order order)`]
- [Apply bit-wise "or" with `v` to variable, returning previous value]
- ]
- [
- [`I fetch_xor(I v, memory_order order)`]
- [Apply bit-wise "xor" with `v` to variable, returning previous value]
- ]
- ]
- Additionally, as a [*Boost.Atomic] extension, the following operations are also provided:
- [table
- [[Syntax] [Description]]
- [
- [`I fetch_negate(memory_order order)`]
- [Change the sign of the value stored in the variable, returning previous value]
- ]
- [
- [`I fetch_complement(memory_order order)`]
- [Set the variable to the one\'s complement of the current value, returning previous value]
- ]
- [
- [`I negate(memory_order order)`]
- [Change the sign of the value stored in the variable, returning the result]
- ]
- [
- [`I add(I v, memory_order order)`]
- [Add `v` to variable, returning the result]
- ]
- [
- [`I sub(I v, memory_order order)`]
- [Subtract `v` from variable, returning the result]
- ]
- [
- [`I bitwise_and(I v, memory_order order)`]
- [Apply bit-wise "and" with `v` to variable, returning the result]
- ]
- [
- [`I bitwise_or(I v, memory_order order)`]
- [Apply bit-wise "or" with `v` to variable, returning the result]
- ]
- [
- [`I bitwise_xor(I v, memory_order order)`]
- [Apply bit-wise "xor" with `v` to variable, returning the result]
- ]
- [
- [`I bitwise_complement(memory_order order)`]
- [Set the variable to the one\'s complement of the current value, returning the result]
- ]
- [
- [`void opaque_negate(memory_order order)`]
- [Change the sign of the value stored in the variable, returning nothing]
- ]
- [
- [`void opaque_add(I v, memory_order order)`]
- [Add `v` to variable, returning nothing]
- ]
- [
- [`void opaque_sub(I v, memory_order order)`]
- [Subtract `v` from variable, returning nothing]
- ]
- [
- [`void opaque_and(I v, memory_order order)`]
- [Apply bit-wise "and" with `v` to variable, returning nothing]
- ]
- [
- [`void opaque_or(I v, memory_order order)`]
- [Apply bit-wise "or" with `v` to variable, returning nothing]
- ]
- [
- [`void opaque_xor(I v, memory_order order)`]
- [Apply bit-wise "xor" with `v` to variable, returning nothing]
- ]
- [
- [`void opaque_complement(memory_order order)`]
- [Set the variable to the one\'s complement of the current value, returning nothing]
- ]
- [
- [`bool negate_and_test(memory_order order)`]
- [Change the sign of the value stored in the variable, returning `true` if the result is non-zero and `false` otherwise]
- ]
- [
- [`bool add_and_test(I v, memory_order order)`]
- [Add `v` to variable, returning `true` if the result is non-zero and `false` otherwise]
- ]
- [
- [`bool sub_and_test(I v, memory_order order)`]
- [Subtract `v` from variable, returning `true` if the result is non-zero and `false` otherwise]
- ]
- [
- [`bool and_and_test(I v, memory_order order)`]
- [Apply bit-wise "and" with `v` to variable, returning `true` if the result is non-zero and `false` otherwise]
- ]
- [
- [`bool or_and_test(I v, memory_order order)`]
- [Apply bit-wise "or" with `v` to variable, returning `true` if the result is non-zero and `false` otherwise]
- ]
- [
- [`bool xor_and_test(I v, memory_order order)`]
- [Apply bit-wise "xor" with `v` to variable, returning `true` if the result is non-zero and `false` otherwise]
- ]
- [
- [`bool complement_and_test(memory_order order)`]
- [Set the variable to the one\'s complement of the current value, returning `true` if the result is non-zero and `false` otherwise]
- ]
- [
- [`bool bit_test_and_set(unsigned int n, memory_order order)`]
- [Set bit number `n` in the variable to 1, returning `true` if the bit was previously set to 1 and `false` otherwise]
- ]
- [
- [`bool bit_test_and_reset(unsigned int n, memory_order order)`]
- [Set bit number `n` in the variable to 0, returning `true` if the bit was previously set to 1 and `false` otherwise]
- ]
- [
- [`bool bit_test_and_complement(unsigned int n, memory_order order)`]
- [Change bit number `n` in the variable to the opposite value, returning `true` if the bit was previously set to 1 and `false` otherwise]
- ]
- ]
- [note In Boost.Atomic 1.66 the [^['op]_and_test] operations returned the opposite value (i.e. `true` if the result is zero). This was changed
- to the current behavior in 1.67 for consistency with other operations in Boost.Atomic, as well as with conventions taken in the C++ standard library.
- Boost.Atomic 1.66 was the only release shipped with the old behavior. Users upgrading from Boost 1.66 to a later release can define
- `BOOST_ATOMIC_HIGHLIGHT_OP_AND_TEST` macro when building their code to generate deprecation warnings on the [^['op]_and_test] function calls
- (the functions are not actually deprecated though; this is just a way to highlight their use).]
- `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`.
- [endsect]
- [section:interface_atomic_floating_point [^boost::atomic<['floating-point]>] template class]
- [note The support for floating point types is optional and can be disabled by defining `BOOST_ATOMIC_NO_FLOATING_POINT`.]
- 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]>]:
- [table
- [[Syntax] [Description]]
- [
- [`F fetch_add(F v, memory_order order)`]
- [Add `v` to variable, returning previous value]
- ]
- [
- [`F fetch_sub(F v, memory_order order)`]
- [Subtract `v` from variable, returning previous value]
- ]
- ]
- Additionally, as a [*Boost.Atomic] extension, the following operations are also provided:
- [table
- [[Syntax] [Description]]
- [
- [`F fetch_negate(memory_order order)`]
- [Change the sign of the value stored in the variable, returning previous value]
- ]
- [
- [`F negate(memory_order order)`]
- [Change the sign of the value stored in the variable, returning the result]
- ]
- [
- [`F add(F v, memory_order order)`]
- [Add `v` to variable, returning the result]
- ]
- [
- [`F sub(F v, memory_order order)`]
- [Subtract `v` from variable, returning the result]
- ]
- [
- [`void opaque_negate(memory_order order)`]
- [Change the sign of the value stored in the variable, returning nothing]
- ]
- [
- [`void opaque_add(F v, memory_order order)`]
- [Add `v` to variable, returning nothing]
- ]
- [
- [`void opaque_sub(F v, memory_order order)`]
- [Subtract `v` from variable, returning nothing]
- ]
- ]
- `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 [@https://en.wikipedia.org/wiki/Denormal_number 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.
- [endsect]
- [section:interface_atomic_pointer [^boost::atomic<['pointer]>] template class]
- 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]>]:
- [table
- [[Syntax] [Description]]
- [
- [`T fetch_add(ptrdiff_t v, memory_order order)`]
- [Add `v` to variable, returning previous value]
- ]
- [
- [`T fetch_sub(ptrdiff_t v, memory_order order)`]
- [Subtract `v` from variable, returning previous value]
- ]
- ]
- Similarly to integers, the following [*Boost.Atomic] extensions are also provided:
- [table
- [[Syntax] [Description]]
- [
- [`void add(ptrdiff_t v, memory_order order)`]
- [Add `v` to variable, returning the result]
- ]
- [
- [`void sub(ptrdiff_t v, memory_order order)`]
- [Subtract `v` from variable, returning the result]
- ]
- [
- [`void opaque_add(ptrdiff_t v, memory_order order)`]
- [Add `v` to variable, returning nothing]
- ]
- [
- [`void opaque_sub(ptrdiff_t v, memory_order order)`]
- [Subtract `v` from variable, returning nothing]
- ]
- [
- [`bool add_and_test(ptrdiff_t v, memory_order order)`]
- [Add `v` to variable, returning `true` if the result is non-null and `false` otherwise]
- ]
- [
- [`bool sub_and_test(ptrdiff_t v, memory_order order)`]
- [Subtract `v` from variable, returning `true` if the result is non-null and `false` otherwise]
- ]
- ]
- `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`.
- [endsect]
- [section:interface_atomic_convenience_typedefs [^boost::atomic<['T]>] convenience typedefs]
- For convenience, several shorthand typedefs of [^boost::atomic<['T]>] are provided:
- [c++]
- 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.
- [endsect]
- [endsect]
- [section:interface_fences Fences]
- #include <boost/atomic/fences.hpp>
- [table
- [[Syntax] [Description]]
- [
- [`void atomic_thread_fence(memory_order order)`]
- [Issue fence for coordination with other threads.]
- ]
- [
- [`void atomic_signal_fence(memory_order order)`]
- [Issue fence for coordination with signal handler (only in same thread).]
- ]
- ]
- [endsect]
- [section:feature_macros Feature testing macros]
- #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:
- [table
- [[Macro] [Description]]
- [
- [`BOOST_ATOMIC_FLAG_LOCK_FREE`]
- [Indicate whether `atomic_flag` is lock-free]
- ]
- [
- [`BOOST_ATOMIC_BOOL_LOCK_FREE`]
- [Indicate whether `atomic<bool>` is lock-free]
- ]
- [
- [`BOOST_ATOMIC_CHAR_LOCK_FREE`]
- [Indicate whether `atomic<char>` (including signed/unsigned variants) is lock-free]
- ]
- [
- [`BOOST_ATOMIC_CHAR16_T_LOCK_FREE`]
- [Indicate whether `atomic<char16_t>` (including signed/unsigned variants) is lock-free]
- ]
- [
- [`BOOST_ATOMIC_CHAR32_T_LOCK_FREE`]
- [Indicate whether `atomic<char32_t>` (including signed/unsigned variants) is lock-free]
- ]
- [
- [`BOOST_ATOMIC_WCHAR_T_LOCK_FREE`]
- [Indicate whether `atomic<wchar_t>` (including signed/unsigned variants) is lock-free]
- ]
- [
- [`BOOST_ATOMIC_SHORT_LOCK_FREE`]
- [Indicate whether `atomic<short>` (including signed/unsigned variants) is lock-free]
- ]
- [
- [`BOOST_ATOMIC_INT_LOCK_FREE`]
- [Indicate whether `atomic<int>` (including signed/unsigned variants) is lock-free]
- ]
- [
- [`BOOST_ATOMIC_LONG_LOCK_FREE`]
- [Indicate whether `atomic<long>` (including signed/unsigned variants) is lock-free]
- ]
- [
- [`BOOST_ATOMIC_LLONG_LOCK_FREE`]
- [Indicate whether `atomic<long long>` (including signed/unsigned variants) is lock-free]
- ]
- [
- [`BOOST_ATOMIC_ADDRESS_LOCK_FREE` or `BOOST_ATOMIC_POINTER_LOCK_FREE`]
- [Indicate whether `atomic<T *>` is lock-free]
- ]
- [
- [`BOOST_ATOMIC_THREAD_FENCE`]
- [Indicate whether `atomic_thread_fence` function is lock-free]
- ]
- [
- [`BOOST_ATOMIC_SIGNAL_FENCE`]
- [Indicate whether `atomic_signal_fence` function is lock-free]
- ]
- ]
- 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.
- [table
- [[Macro] [Description]]
- [
- [`BOOST_ATOMIC_INT8_LOCK_FREE`]
- [Indicate whether `atomic<int8_type>` is lock-free.]
- ]
- [
- [`BOOST_ATOMIC_INT16_LOCK_FREE`]
- [Indicate whether `atomic<int16_type>` is lock-free.]
- ]
- [
- [`BOOST_ATOMIC_INT32_LOCK_FREE`]
- [Indicate whether `atomic<int32_type>` is lock-free.]
- ]
- [
- [`BOOST_ATOMIC_INT64_LOCK_FREE`]
- [Indicate whether `atomic<int64_type>` is lock-free.]
- ]
- [
- [`BOOST_ATOMIC_INT128_LOCK_FREE`]
- [Indicate whether `atomic<int128_type>` is lock-free.]
- ]
- [
- [`BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT`]
- [Defined after including `atomic_flag.hpp`, if the implementation
- does not support the `BOOST_ATOMIC_FLAG_INIT` macro for static
- initialization of `atomic_flag`. This macro is typically defined
- for pre-C++11 compilers.]
- ]
- ]
- 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:
- [table
- [[Macro] [Description]]
- [
- [`BOOST_ATOMIC_FLOAT_LOCK_FREE`]
- [Indicate whether `atomic<float>` is lock-free.]
- ]
- [
- [`BOOST_ATOMIC_DOUBLE_LOCK_FREE`]
- [Indicate whether `atomic<double>` is lock-free.]
- ]
- [
- [`BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE`]
- [Indicate whether `atomic<long double>` is lock-free.]
- ]
- ]
- These macros are not defined when support for floating point types is disabled by user.
- [endsect]
- [endsect]
- [section:usage_examples Usage examples]
- [include examples.qbk]
- [endsect]
- [/
- [section:platform_support Implementing support for additional platforms]
- [include platform.qbk]
- [endsect]
- ]
- [/ [xinclude autodoc.xml] ]
- [section:limitations 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 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.
- * [*Default constructor is not trivial in C++03]: Because the initializing
- constructor has to be defined in `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).
- * [*C++03 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 [@https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59448 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 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.
- * [*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`.
- * [*Signed integers must use [@https://en.wikipedia.org/wiki/Two%27s_complement 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.
- [endsect]
- [section:porting Porting]
- [section:unit_tests Unit tests]
- [*Boost.Atomic] provides a unit test suite to verify that the
- implementation behaves as expected:
- * [*fallback_api.cpp] verifies that the fallback-to-locking aspect
- of [*Boost.Atomic] compiles and has correct value semantics.
- * [*native_api.cpp] verifies that all atomic operations have correct
- value semantics (e.g. "fetch_add" really adds the desired value,
- returning the previous). It is a rough "smoke-test" to help weed
- out the most obvious mistakes (for example width overflow,
- signed/unsigned extension, ...).
- * [*lockfree.cpp] verifies that the [*BOOST_ATOMIC_*_LOCKFREE] macros
- are set properly according to the expectations for a given
- platform, and that they match up with the [*is_always_lock_free] and
- [*is_lock_free] members of the [*atomic] object instances.
- * [*atomicity.cpp] lets two threads race against each other modifying
- a shared variable, verifying that the operations behave atomic
- as appropriate. By nature, this test is necessarily stochastic, and
- the test self-calibrates to yield 99% confidence that a
- positive result indicates absence of an error. This test is
- very useful on uni-processor systems with preemption already.
- * [*ordering.cpp] lets two threads race against each other accessing
- multiple shared variables, verifying that the operations
- exhibit the expected ordering behavior. By nature, this test is
- necessarily stochastic, and the test attempts to self-calibrate to
- yield 99% confidence that a positive result indicates absence
- of an error. This only works on true multi-processor (or multi-core)
- systems. It does not yield any result on uni-processor systems
- or emulators (due to there being no observable reordering even
- the order=relaxed case) and will report that fact.
- [endsect]
- [section:tested_compilers Tested compilers]
- [*Boost.Atomic] has been tested on and is known to work on
- the following compilers/platforms:
- * gcc 4.x: i386, x86_64, ppc32, ppc64, sparcv9, armv6, alpha
- * Visual Studio Express 2008/Windows XP, x86, x64, ARM
- [endsect]
- [section:acknowledgements Acknowledgements]
- * Adam Wulkiewicz created the logo used on the [@https://github.com/boostorg/atomic GitHub project page]. The logo was taken from his [@https://github.com/awulkiew/boost-logos collection] of Boost logos.
- [endsect]
- [endsect]
|