|
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 | +//! |
36 | 42 | //! The end result is *almost* equivalent to saying that creating a *shared reference* to one of the
|
37 | 43 | //! Rust atomic types corresponds to creating an `atomic_ref` in C++, with the `atomic_ref` being
|
38 | 44 | //! destroyed when the lifetime of the shared reference ends. The main difference is that Rust
|
|
41 | 47 | //! objects" and "non-atomic objects" (with `atomic_ref` temporarily converting a non-atomic object
|
42 | 48 | //! into an atomic object).
|
43 | 49 | //!
|
44 |
| -//! That said, Rust *does* inherit the C++ limitation that non-synchronized atomic accesses may not |
45 |
| -//! partially overlap: they must be either disjoint or access the exact same memory. This in |
46 |
| -//! particular rules out non-synchronized differently-sized accesses to the same data. |
| 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. |
47 | 54 | //!
|
48 | 55 | //! [cpp]: https://en.cppreference.com/w/cpp/atomic
|
49 | 56 | //! [cpp-intro.races]: https://timsong-cpp.github.io/cppwp/n4868/intro.multithread#intro.races
|
|
63 | 70 | //! let atomic = AtomicU16::new(0);
|
64 | 71 | //!
|
65 | 72 | //! thread::scope(|s| {
|
66 |
| -//! // This is UB: conflicting concurrent accesses. |
| 73 | +//! // This is UB: conflicting non-synchronized accesses, at least one of which is non-atomic. |
67 | 74 | //! s.spawn(|| atomic.store(1, Ordering::Relaxed)); // atomic store
|
68 | 75 | //! s.spawn(|| unsafe { atomic.as_ptr().write(2) }); // non-atomic write
|
69 | 76 | //! });
|
|
77 | 84 | //! });
|
78 | 85 | //!
|
79 | 86 | //! thread::scope(|s| {
|
80 |
| -//! // This is fine, `join` synchronizes the code in a way such that atomic |
81 |
| -//! // and non-atomic accesses can't happen "at the same time". |
| 87 | +//! // This is fine: `join` synchronizes the code in a way such that the atomic |
| 88 | +//! // store happens-before the non-atomic write. |
82 | 89 | //! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed)); // atomic store
|
83 | 90 | //! handle.join().unwrap(); // synchronize
|
84 | 91 | //! s.spawn(|| unsafe { atomic.as_ptr().write(2) }); // non-atomic write
|
85 | 92 | //! });
|
86 | 93 | //!
|
87 | 94 | //! thread::scope(|s| {
|
88 |
| -//! // This is UB: using differently-sized atomic accesses to the same data. |
89 |
| -//! // (It would be UB even if these are both loads.) |
| 95 | +//! // This is UB: non-synchronized conflicting differently-sized atomic accesses. |
90 | 96 | //! s.spawn(|| atomic.store(1, Ordering::Relaxed));
|
91 | 97 | //! s.spawn(|| unsafe {
|
92 | 98 | //! let differently_sized = transmute::<&AtomicU16, &AtomicU8>(&atomic);
|
|
95 | 101 | //! });
|
96 | 102 | //!
|
97 | 103 | //! thread::scope(|s| {
|
98 |
| -//! // This is fine, `join` synchronizes the code in a way such that |
99 |
| -//! // differently-sized accesses can't happen "at the same time". |
| 104 | +//! // This is fine: `join` synchronizes the code in a way such that |
| 105 | +//! // the 1-byte store happens-before the 2-byte store. |
100 | 106 | //! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed));
|
101 | 107 | //! handle.join().unwrap();
|
102 | 108 | //! s.spawn(|| unsafe {
|
|
0 commit comments