|  | 
| 33 | 33 | //! atomic load (via the operations provided in this module). A "modification of an atomic object" | 
| 34 | 34 | //! refers to an atomic store. | 
| 35 | 35 | //! | 
| 36 |  | -//! The most important aspect of this model is that conflicting non-synchronized accesses are | 
| 37 |  | -//! Undefined Behavior unless both accesses are atomic. Here, accesses are *conflicting* if they | 
| 38 |  | -//! affect overlapping regions of memory and at least one of them is a write. They are | 
| 39 |  | -//! *non-synchronized* if neither of them *happens-before* the other, according to the | 
| 40 |  | -//! happens-before order of the memory model. | 
| 41 |  | -//! | 
| 42 | 36 | //! The end result is *almost* equivalent to saying that creating a *shared reference* to one of the | 
| 43 | 37 | //! Rust atomic types corresponds to creating an `atomic_ref` in C++, with the `atomic_ref` being | 
| 44 | 38 | //! destroyed when the lifetime of the shared reference ends. The main difference is that Rust | 
|  | 
| 47 | 41 | //! objects" and "non-atomic objects" (with `atomic_ref` temporarily converting a non-atomic object | 
| 48 | 42 | //! into an atomic object). | 
| 49 | 43 | //! | 
| 50 |  | -//! That said, Rust *does* inherit the C++ limitation that non-synchronized conflicting atomic | 
| 51 |  | -//! accesses may not partially overlap: they must be either disjoint or access the exact same | 
| 52 |  | -//! memory. This in particular rules out non-synchronized differently-sized atomic accesses to the | 
| 53 |  | -//! same data unless all accesses are reads. | 
|  | 44 | +//! The most important aspect of this model is that *data races* are undefined behavior. A data race | 
|  | 45 | +//! is defined as conflicting non-synchronized accesses where at least one of the accesses is | 
|  | 46 | +//! non-atomic. Here, accesses are *conflicting* if they affect overlapping regions of memory and at | 
|  | 47 | +//! least one of them is a write. They are *non-synchronized* if neither of them *happens-before* | 
|  | 48 | +//! the other, according to the happens-before order of the memory model. | 
| 54 | 49 | //! | 
| 55 |  | -//! [cpp]: https://en.cppreference.com/w/cpp/atomic | 
| 56 |  | -//! [cpp-intro.races]: https://timsong-cpp.github.io/cppwp/n4868/intro.multithread#intro.races | 
|  | 50 | +//! The other possible cause of undefined behavior in the memory model are mixed-size accesses: Rust | 
|  | 51 | +//! inherits the C++ limitation that non-synchronized conflicting atomic accesses may not partially | 
|  | 52 | +//! overlap. In other words, every pair of non-synchronized atomic accesses must be either disjoint, | 
|  | 53 | +//! access the exact same memory (including using the same access size), or both be reads. | 
| 57 | 54 | //! | 
| 58 |  | -//! Each method takes an [`Ordering`] which represents the strength of | 
| 59 |  | -//! the memory barrier for that operation. These orderings behave the | 
| 60 |  | -//! same as the corresponding [C++20 atomic orderings][1]. For more information see the [nomicon][2]. | 
|  | 55 | +//! Each atomic access takes an [`Ordering`] which defines how the operation interacts with the | 
|  | 56 | +//! happens-before order. These orderings behave the same as the corresponding [C++20 atomic | 
|  | 57 | +//! orderings][cpp_memory_order]. For more information, see the [nomicon]. | 
| 61 | 58 | //! | 
| 62 |  | -//! [1]: https://en.cppreference.com/w/cpp/atomic/memory_order | 
| 63 |  | -//! [2]: ../../../nomicon/atomics.html | 
|  | 59 | +//! [cpp]: https://en.cppreference.com/w/cpp/atomic | 
|  | 60 | +//! [cpp-intro.races]: https://timsong-cpp.github.io/cppwp/n4868/intro.multithread#intro.races | 
|  | 61 | +//! [cpp_memory_order]: https://en.cppreference.com/w/cpp/atomic/memory_order | 
|  | 62 | +//! [nomicon]: ../../../nomicon/atomics.html | 
| 64 | 63 | //! | 
| 65 | 64 | //! ```rust,no_run undefined_behavior | 
| 66 | 65 | //! use std::sync::atomic::{AtomicU16, AtomicU8, Ordering}; | 
|  | 
| 157 | 156 | //! | 
| 158 | 157 | //! # Atomic accesses to read-only memory | 
| 159 | 158 | //! | 
| 160 |  | -//! In general, *all* atomic accesses on read-only memory are Undefined Behavior. For instance, attempting | 
|  | 159 | +//! In general, *all* atomic accesses on read-only memory are undefined behavior. For instance, attempting | 
| 161 | 160 | //! to do a `compare_exchange` that will definitely fail (making it conceptually a read-only | 
| 162 | 161 | //! operation) can still cause a segmentation fault if the underlying memory page is mapped read-only. Since | 
| 163 | 162 | //! atomic `load`s might be implemented using compare-exchange operations, even a `load` can fault | 
|  | 
| 173 | 172 | //! | 
| 174 | 173 | //! As an exception from the general rule stated above, "sufficiently small" atomic loads with | 
| 175 | 174 | //! `Ordering::Relaxed` are implemented in a way that works on read-only memory, and are hence not | 
| 176 |  | -//! Undefined Behavior. The exact size limit for what makes a load "sufficiently small" varies | 
|  | 175 | +//! undefined behavior. The exact size limit for what makes a load "sufficiently small" varies | 
| 177 | 176 | //! depending on the target: | 
| 178 | 177 | //! | 
| 179 | 178 | //! | `target_arch` | Size limit | | 
|  | 
0 commit comments