Expand description
Atomic types
Atomic types provide primitive shared-memory communication between threads, and are the building blocks of other concurrent types.
This module defines atomic versions of a select number of primitive
types, including AtomicBool
, AtomicIsize
, AtomicUsize
,
AtomicI8
, AtomicU16
, etc.
Atomic types present operations that, when used correctly, synchronize
updates between threads.
Atomic variables are safe to share between threads (they implement Sync
)
but they do not themselves provide the mechanism for sharing and follow the
threading model of Rust.
The most common way to share an atomic variable is to put it into an Arc
(an
atomically-reference-counted shared pointer).
Atomic types may be stored in static variables, initialized using
the constant initializers like AtomicBool::new
. Atomic statics
are often used for lazy global initialization.
§Memory model for atomic accesses
Rust atomics currently follow the same rules as C++20 atomics, specifically the rules
from the intro.races
section, without the “consume” memory ordering. Since
C++ uses an object-based memory model whereas Rust is access-based, a bit of translation work
has to be done to apply the C++ rules to Rust: whenever C++ talks about “the value of an
object”, we understand that to mean the resulting bytes obtained when doing a read. When the C++
standard talks about “the value of an atomic object”, this refers to the result of doing an
atomic load (via the operations provided in this module). A “modification of an atomic object”
refers to an atomic store.
The end result is almost equivalent to saying that creating a shared reference to one of the
Rust atomic types corresponds to creating an atomic_ref
in C++, with the atomic_ref
being
destroyed when the lifetime of the shared reference ends. The main difference is that Rust
permits concurrent atomic and non-atomic reads to the same memory as those cause no issue in the
C++ memory model, they are just forbidden in C++ because memory is partitioned into “atomic
objects” and “non-atomic objects” (with atomic_ref
temporarily converting a non-atomic object
into an atomic object).
The most important aspect of this model is that data races are undefined behavior. A data race is defined as conflicting non-synchronized accesses where at least one of the accesses is non-atomic. Here, accesses are conflict