Rollup merge of #142252 - fu5ha:doc-cas-ops, r=ibraheemdev

Improve clarity of `core::sync::atomic` docs about "Considerations" in regards to CAS operations

## Motivation

The existing documentation for atomic `fetch_update` (and other similar methods) has a section that reads like so:

> ### Considerations
> This method is not magic; it is not provided by the hardware. It is implemented in
> terms of `AtomicBlah::compare_exchange_weak`, and suffers from the same drawbacks.
> In particular, this method will not circumvent the [ABA Problem].
>
> [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem

The wording here seems to imply that the drawbacks being discusses are caused by the *`weak` version* of `compare_exchange`, and that one may avoid those drawbacks by using `compare_exchange` instead. Indeed, a conversation in the `#dark-arts` channel on the Rust community discord based on this interpretation led to this PR.

In reality, the drawbacks are inherent to implementing such an operation based on *any* compare-and-swap style operation, as opposed to an [LL,SC](https://en.wikipedia.org/wiki/Load-link/store-conditional) operation, and they apply equally to `compare_exchange` and `compare_exchange_weak` as well.

## Changes

- Rewords existing Considerations section on `fetch_update` and friends to make clear that the limitations are inherent to an implementation based on any CAS operation, rather than the weak version of `compare_exchange` in particular. New version:

> ### Considerations
>
> This method is not magic; it is not provided by the hardware, and does not act like a
> critical section or mutex.
>
> It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
> the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]
> if this atomic integer is an index or more generally if knowledge of only the *bitwise value*
> of the atomic is not in and of itself sufficient to ensure any required preconditions.
>
> [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
> [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap

- Add Considerations to `compare_exchange` and `compare_exchange_weak` which details similar considerations and when they may be relevant. New version:

> ### Considerations
>
> `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
> of CAS operations. In particular, a load of the value followed by a successful
> `compare_exchange` with the previous load *does not ensure* that other threads have not
> changed the value in the interim. This is usually important when the *equality* check in
> the `compare_exchange` is being used to check the *identity* of a value, but equality
> does not necessarily imply identity. In this case, `compare_exchange` can lead to the
> [ABA problem].
>
> [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
> [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
This commit is contained in:
Matthias Krüger 2025-06-12 20:03:37 +02:00 committed by GitHub
commit 764be85223
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -891,6 +891,19 @@ impl AtomicBool {
/// Err(false));
/// assert_eq!(some_bool.load(Ordering::Relaxed), false);
/// ```
///
/// # Considerations
///
/// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
/// of CAS operations. In particular, a load of the value followed by a successful
/// `compare_exchange` with the previous load *does not ensure* that other threads have not
/// changed the value in the interim. This is usually important when the *equality* check in
/// the `compare_exchange` is being used to check the *identity* of a value, but equality
/// does not necessarily imply identity. In this case, `compare_exchange` can lead to the
/// [ABA problem].
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
#[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
#[doc(alias = "compare_and_swap")]
@ -973,6 +986,19 @@ impl AtomicBool {
/// }
/// }
/// ```
///
/// # Considerations
///
/// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
/// of CAS operations. In particular, a load of the value followed by a successful
/// `compare_exchange` with the previous load *does not ensure* that other threads have not
/// changed the value in the interim. This is usually important when the *equality* check in
/// the `compare_exchange` is being used to check the *identity* of a value, but equality
/// does not necessarily imply identity. In this case, `compare_exchange` can lead to the
/// [ABA problem].
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
#[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
#[doc(alias = "compare_and_swap")]
@ -1271,11 +1297,14 @@ impl AtomicBool {
///
/// # Considerations
///
/// This method is not magic; it is not provided by the hardware.
/// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks.
/// In particular, this method will not circumvent the [ABA Problem].
/// This method is not magic; it is not provided by the hardware, and does not act like a
/// critical section or mutex.
///
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem].
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
///
/// # Examples
///
@ -1338,11 +1367,14 @@ impl AtomicBool {
///
/// # Considerations
///
/// This method is not magic; it is not provided by the hardware.
/// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks.
/// In particular, this method will not circumvent the [ABA Problem].
/// This method is not magic; it is not provided by the hardware, and does not act like a
/// critical section or mutex.
///
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem].
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
///
/// # Examples
///
@ -1393,11 +1425,14 @@ impl AtomicBool {
///
/// # Considerations
///
/// This method is not magic; it is not provided by the hardware.
/// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks.
/// In particular, this method will not circumvent the [ABA Problem].
/// This method is not magic; it is not provided by the hardware, and does not act like a
/// critical section or mutex.
///
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem].
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
///
/// # Examples
///
@ -1825,6 +1860,20 @@ impl<T> AtomicPtr<T> {
/// let value = some_ptr.compare_exchange(ptr, other_ptr,
/// Ordering::SeqCst, Ordering::Relaxed);
/// ```
///
/// # Considerations
///
/// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
/// of CAS operations. In particular, a load of the value followed by a successful
/// `compare_exchange` with the previous load *does not ensure* that other threads have not
/// changed the value in the interim. This is usually important when the *equality* check in
/// the `compare_exchange` is being used to check the *identity* of a value, but equality
/// does not necessarily imply identity. This is a particularly common case for pointers, as
/// a pointer holding the same address does not imply that the same object exists at that
/// address! In this case, `compare_exchange` can lead to the [ABA problem].
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
#[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
#[cfg(target_has_atomic = "ptr")]
@ -1874,6 +1923,20 @@ impl<T> AtomicPtr<T> {
/// }
/// }
/// ```
///
/// # Considerations
///
/// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
/// of CAS operations. In particular, a load of the value followed by a successful
/// `compare_exchange` with the previous load *does not ensure* that other threads have not
/// changed the value in the interim. This is usually important when the *equality* check in
/// the `compare_exchange` is being used to check the *identity* of a value, but equality
/// does not necessarily imply identity. This is a particularly common case for pointers, as
/// a pointer holding the same address does not imply that the same object exists at that
/// address! In this case, `compare_exchange` can lead to the [ABA problem].
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
#[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
#[cfg(target_has_atomic = "ptr")]
@ -1917,11 +1980,15 @@ impl<T> AtomicPtr<T> {
///
/// # Considerations
///
/// This method is not magic; it is not provided by the hardware.
/// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks.
/// In particular, this method will not circumvent the [ABA Problem].
/// This method is not magic; it is not provided by the hardware, and does not act like a
/// critical section or mutex.
///
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem],
/// which is a particularly common pitfall for pointers!
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
///
/// # Examples
///
@ -1992,11 +2059,15 @@ impl<T> AtomicPtr<T> {
///
/// # Considerations
///
/// This method is not magic; it is not provided by the hardware.
/// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks.
/// In particular, this method will not circumvent the [ABA Problem].
/// This method is not magic; it is not provided by the hardware, and does not act like a
/// critical section or mutex.
///
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem],
/// which is a particularly common pitfall for pointers!
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
///
/// # Examples
///
@ -2057,11 +2128,15 @@ impl<T> AtomicPtr<T> {
///
/// # Considerations
///
/// This method is not magic; it is not provided by the hardware.
/// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks.
/// In particular, this method will not circumvent the [ABA Problem].
/// This method is not magic; it is not provided by the hardware, and does not act like a
/// critical section or mutex.
///
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem],
/// which is a particularly common pitfall for pointers!
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
///
/// # Examples
///
@ -2967,6 +3042,20 @@ macro_rules! atomic_int {
/// Err(10));
/// assert_eq!(some_var.load(Ordering::Relaxed), 10);
/// ```
///
/// # Considerations
///
/// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
/// of CAS operations. In particular, a load of the value followed by a successful
/// `compare_exchange` with the previous load *does not ensure* that other threads have not
/// changed the value in the interim! This is usually important when the *equality* check in
/// the `compare_exchange` is being used to check the *identity* of a value, but equality
/// does not necessarily imply identity. This is a particularly common case for pointers, as
/// a pointer holding the same address does not imply that the same object exists at that
/// address! In this case, `compare_exchange` can lead to the [ABA problem].
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
#[inline]
#[$stable_cxchg]
#[$cfg_cas]
@ -3016,6 +3105,20 @@ macro_rules! atomic_int {
/// }
/// }
/// ```
///
/// # Considerations
///
/// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
/// of CAS operations. In particular, a load of the value followed by a successful
/// `compare_exchange` with the previous load *does not ensure* that other threads have not
/// changed the value in the interim. This is usually important when the *equality* check in
/// the `compare_exchange` is being used to check the *identity* of a value, but equality
/// does not necessarily imply identity. This is a particularly common case for pointers, as
/// a pointer holding the same address does not imply that the same object exists at that
/// address! In this case, `compare_exchange` can lead to the [ABA problem].
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
#[inline]
#[$stable_cxchg]
#[$cfg_cas]
@ -3246,13 +3349,16 @@ macro_rules! atomic_int {
///
/// # Considerations
///
/// This method is not magic; it is not provided by the hardware.
/// It is implemented in terms of
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")]
/// and suffers from the same drawbacks.
/// In particular, this method will not circumvent the [ABA Problem].
/// This method is not magic; it is not provided by the hardware, and does not act like a
/// critical section or mutex.
///
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]
/// if this atomic integer is an index or more generally if knowledge of only the *bitwise value*
/// of the atomic is not in and of itself sufficient to ensure any required preconditions.
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
///
/// # Examples
///
@ -3309,13 +3415,16 @@ macro_rules! atomic_int {
///
/// # Considerations
///
/// This method is not magic; it is not provided by the hardware.
/// It is implemented in terms of
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")]
/// and suffers from the same drawbacks.
/// In particular, this method will not circumvent the [ABA Problem].
/// This method is not magic; it is not provided by the hardware, and does not act like a
/// critical section or mutex.
///
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]
/// if this atomic integer is an index or more generally if knowledge of only the *bitwise value*
/// of the atomic is not in and of itself sufficient to ensure any required preconditions.
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
///
/// # Examples
///
@ -3367,13 +3476,17 @@ macro_rules! atomic_int {
///
/// # Considerations
///
/// This method is not magic; it is not provided by the hardware.
/// It is implemented in terms of
#[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")]
/// and suffers from the same drawbacks.
/// In particular, this method will not circumvent the [ABA Problem].
/// [CAS operation]: https://en.wikipedia.org/wiki/Compare-and-swap
/// This method is not magic; it is not provided by the hardware, and does not act like a
/// critical section or mutex.
///
/// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
/// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]
/// if this atomic integer is an index or more generally if knowledge of only the *bitwise value*
/// of the atomic is not in and of itself sufficient to ensure any required preconditions.
///
/// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
/// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
///
/// # Examples
///