|
4 | 4 | //! threads, and are the building blocks of other concurrent
|
5 | 5 | //! types.
|
6 | 6 | //!
|
7 |
| -//! Rust atomics currently follow the same rules as [C++20 atomics][cpp], specifically `atomic_ref`. |
8 |
| -//! Basically, creating a *shared reference* to one of the Rust atomic types corresponds to creating |
9 |
| -//! an `atomic_ref` in C++; the `atomic_ref` is destroyed when the lifetime of the shared reference |
10 |
| -//! ends. (A Rust atomic type that is exclusively owned or behind a mutable reference does *not* |
11 |
| -//! correspond to an "atomic object" in C++, since it can be accessed via non-atomic operations.) |
12 |
| -//! |
13 | 7 | //! This module defines atomic versions of a select number of primitive
|
14 | 8 | //! types, including [`AtomicBool`], [`AtomicIsize`], [`AtomicUsize`],
|
15 | 9 | //! [`AtomicI8`], [`AtomicU16`], etc.
|
16 | 10 | //! Atomic types present operations that, when used correctly, synchronize
|
17 | 11 | //! updates between threads.
|
18 | 12 | //!
|
19 |
| -//! Each method takes an [`Ordering`] which represents the strength of |
20 |
| -//! the memory barrier for that operation. These orderings are the |
21 |
| -//! same as the [C++20 atomic orderings][1]. For more information see the [nomicon][2]. |
22 |
| -//! |
23 |
| -//! [cpp]: https://en.cppreference.com/w/cpp/atomic |
24 |
| -//! [1]: https://en.cppreference.com/w/cpp/atomic/memory_order |
25 |
| -//! [2]: ../../../nomicon/atomics.html |
26 |
| -//! |
27 | 13 | //! Atomic variables are safe to share between threads (they implement [`Sync`])
|
28 | 14 | //! but they do not themselves provide the mechanism for sharing and follow the
|
29 | 15 | //! [threading model](../../../std/thread/index.html#the-threading-model) of Rust.
|
|
36 | 22 | //! the constant initializers like [`AtomicBool::new`]. Atomic statics
|
37 | 23 | //! are often used for lazy global initialization.
|
38 | 24 | //!
|
| 25 | +//! ## Memory model for atomic accesses |
| 26 | +//! |
| 27 | +//! Rust atomics currently follow the same rules as [C++20 atomics][cpp], specifically `atomic_ref`. |
| 28 | +//! Basically, creating a *shared reference* to one of the Rust atomic types corresponds to creating |
| 29 | +//! an `atomic_ref` in C++; the `atomic_ref` is destroyed when the lifetime of the shared reference |
| 30 | +//! ends. (A Rust atomic type that is exclusively owned or behind a mutable reference does *not* |
| 31 | +//! correspond to an "atomic object" in C++, since it can be accessed via non-atomic operations.) |
| 32 | +//! |
| 33 | +//! [cpp]: https://en.cppreference.com/w/cpp/atomic |
| 34 | +//! |
| 35 | +//! Each method takes an [`Ordering`] which represents the strength of |
| 36 | +//! the memory barrier for that operation. These orderings are the |
| 37 | +//! same as the [C++20 atomic orderings][1]. For more information see the [nomicon][2]. |
| 38 | +//! |
| 39 | +//! [1]: https://en.cppreference.com/w/cpp/atomic/memory_order |
| 40 | +//! [2]: ../../../nomicon/atomics.html |
| 41 | +//! |
| 42 | +//! Since C++ does not support mixing atomic and non-atomic accesses, or non-synchronized |
| 43 | +//! different-sized accesses to the same data, Rust does not support those operations either. |
| 44 | +//! Note that both of those restrictions only apply if the accesses are non-synchronized. |
| 45 | +//! |
| 46 | +//! ```rust,no_run undefined_behavior |
| 47 | +//! use std::sync::atomic::{AtomicU16, AtomicU8, Ordering}; |
| 48 | +//! use std::mem::transmute; |
| 49 | +//! use std::thread; |
| 50 | +//! |
| 51 | +//! let atomic = AtomicU16::new(0); |
| 52 | +//! |
| 53 | +//! thread::scope(|s| { |
| 54 | +//! // This is UB: mixing atomic and non-atomic accesses |
| 55 | +//! s.spawn(|| atomic.store(1, Ordering::Relaxed)); |
| 56 | +//! s.spawn(|| unsafe { |
| 57 | +//! let ptr: *mut u16 = atomic.as_ptr(); |
| 58 | +//! *ptr = 2; |
| 59 | +//! }); |
| 60 | +//! }); |
| 61 | +//! |
| 62 | +//! thread::scope(|s| { |
| 63 | +//! // This is fine, `join` synchronizes the code in a way such that atomic |
| 64 | +//! // and non-atomic accesses can't happen "at the same time" |
| 65 | +//! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed)); |
| 66 | +//! handle.join().unwrap(); |
| 67 | +//! s.spawn(|| unsafe { |
| 68 | +//! let ptr: *mut u16 = atomic.as_ptr(); |
| 69 | +//! *ptr = 2; |
| 70 | +//! }); |
| 71 | +//! }); |
| 72 | +//! |
| 73 | +//! thread::scope(|s| { |
| 74 | +//! // This is UB: using different-sized atomic accesses to the same data |
| 75 | +//! s.spawn(|| atomic.store(1, Ordering::Relaxed)); |
| 76 | +//! s.spawn(|| unsafe { |
| 77 | +//! let differently_sized = transmute::<&AtomicU16, &AtomicU8>(&atomic); |
| 78 | +//! differently_sized.store(2, Ordering::Relaxed); |
| 79 | +//! }); |
| 80 | +//! }); |
| 81 | +//! |
| 82 | +//! thread::scope(|s| { |
| 83 | +//! // This is fine, `join` synchronizes the code in a way such that |
| 84 | +//! // differently-sized accesses can't happen "at the same time" |
| 85 | +//! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed)); |
| 86 | +//! handle.join().unwrap(); |
| 87 | +//! s.spawn(|| unsafe { |
| 88 | +//! let differently_sized = transmute::<&AtomicU16, &AtomicU8>(&atomic); |
| 89 | +//! differently_sized.store(2, Ordering::Relaxed); |
| 90 | +//! }); |
| 91 | +//! }); |
| 92 | +//! ``` |
| 93 | +//! |
39 | 94 | //! # Portability
|
40 | 95 | //!
|
41 | 96 | //! All atomic types in this module are guaranteed to be [lock-free] if they're
|
@@ -349,16 +404,10 @@ impl AtomicBool {
|
349 | 404 | /// * `ptr` must be aligned to `align_of::<AtomicBool>()` (note that on some platforms this can
|
350 | 405 | /// be bigger than `align_of::<bool>()`).
|
351 | 406 | /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
|
352 |
| - /// * Non-atomic accesses to the value behind `ptr` must have a happens-before relationship |
353 |
| - /// with atomic accesses via the returned value (or vice-versa). |
354 |
| - /// * In other words, time periods where the value is accessed atomically may not overlap |
355 |
| - /// with periods where the value is accessed non-atomically. |
356 |
| - /// * This requirement is trivially satisfied if `ptr` is never used non-atomically for the |
357 |
| - /// duration of lifetime `'a`. Most use cases should be able to follow this guideline. |
358 |
| - /// * This requirement is also trivially satisfied if all accesses (atomic or not) are done |
359 |
| - /// from the same thread. |
| 407 | + /// * You must adhere to the [Memory model for atomic accesses]. |
360 | 408 | ///
|
361 | 409 | /// [valid]: crate::ptr#safety
|
| 410 | + /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses |
362 | 411 | #[stable(feature = "atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")]
|
363 | 412 | #[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")]
|
364 | 413 | pub const unsafe fn from_ptr<'a>(ptr: *mut bool) -> &'a AtomicBool {
|
@@ -1151,18 +1200,10 @@ impl<T> AtomicPtr<T> {
|
1151 | 1200 | /// * `ptr` must be aligned to `align_of::<AtomicPtr<T>>()` (note that on some platforms this
|
1152 | 1201 | /// can be bigger than `align_of::<*mut T>()`).
|
1153 | 1202 | /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
|
1154 |
| - /// * Non-atomic accesses to the value behind `ptr` must have a happens-before relationship |
1155 |
| - /// with atomic accesses via the returned value (or vice-versa). |
1156 |
| - /// * In other words, time periods where the value is accessed atomically may not overlap |
1157 |
| - /// with periods where the value is accessed non-atomically. |
1158 |
| - /// * This requirement is trivially satisfied if `ptr` is never used non-atomically for the |
1159 |
| - /// duration of lifetime `'a`. Most use cases should be able to follow this guideline. |
1160 |
| - /// * This requirement is also trivially satisfied if all accesses (atomic or not) are done |
1161 |
| - /// from the same thread. |
1162 |
| - /// * This method should not be used to create overlapping or mixed-size atomic accesses, as |
1163 |
| - /// these are not supported by the memory model. |
| 1203 | + /// * You must adhere to the [Memory model for atomic accesses]. |
1164 | 1204 | ///
|
1165 | 1205 | /// [valid]: crate::ptr#safety
|
| 1206 | + /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses |
1166 | 1207 | #[stable(feature = "atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")]
|
1167 | 1208 | #[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")]
|
1168 | 1209 | pub const unsafe fn from_ptr<'a>(ptr: *mut *mut T) -> &'a AtomicPtr<T> {
|
@@ -2133,19 +2174,10 @@ macro_rules! atomic_int {
|
2133 | 2174 | `align_of::<", stringify!($atomic_type), ">()` (note that on some platforms this \
|
2134 | 2175 | can be bigger than `align_of::<", stringify!($int_type), ">()`).")]
|
2135 | 2176 | /// * `ptr` must be [valid] for both reads and writes for the whole lifetime `'a`.
|
2136 |
| - /// * Non-atomic accesses to the value behind `ptr` must have a happens-before |
2137 |
| - /// relationship with atomic accesses via the returned value (or vice-versa). |
2138 |
| - /// * In other words, time periods where the value is accessed atomically may not |
2139 |
| - /// overlap with periods where the value is accessed non-atomically. |
2140 |
| - /// * This requirement is trivially satisfied if `ptr` is never used non-atomically |
2141 |
| - /// for the duration of lifetime `'a`. Most use cases should be able to follow |
2142 |
| - /// this guideline. |
2143 |
| - /// * This requirement is also trivially satisfied if all accesses (atomic or not) are |
2144 |
| - /// done from the same thread. |
2145 |
| - /// * This method should not be used to create overlapping or mixed-size atomic |
2146 |
| - /// accesses, as these are not supported by the memory model. |
| 2177 | + /// * You must adhere to the [Memory model for atomic accesses]. |
2147 | 2178 | ///
|
2148 | 2179 | /// [valid]: crate::ptr#safety
|
| 2180 | + /// [Memory model for atomic accesses]: self#memory-model-for-atomic-accesses |
2149 | 2181 | #[stable(feature = "atomic_from_ptr", since = "CURRENT_RUSTC_VERSION")]
|
2150 | 2182 | #[rustc_const_unstable(feature = "const_atomic_from_ptr", issue = "108652")]
|
2151 | 2183 | pub const unsafe fn from_ptr<'a>(ptr: *mut $int_type) -> &'a $atomic_type {
|
|
0 commit comments