|
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