std::atomic...nge_strong,(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

πŸ’– std::atomic_compare_exchange_weak,std::atomic_compare_exchange_strong πŸ’–

okay so bestie, this is a C++ Standard Library page β€” the manpage label is std::atomic...nge_strong,(3) if your terminal is doing that truncation thing β€” and it's all about the atomic compare-and-exchange besties. no cap, these are the little atomic matchmakers that check a value, swap it if it matches, and hand back the truth. πŸ’…βœ¨


🌸 NAME 🌸

std::atomic_compare_exchange_weak,std::atomic_compare_exchange_strong, β€” the weak and strong atomic compare-and-exchange function templates. periodt.


✨ Synopsis ✨

Defined in header <atomic>. All of these are (since C++11) and all of them are noexcept. 🫢

(1) (since C++11)

template< class T >
bool atomic_compare_exchange_weak
    ( std::atomic<T>* obj, typename std::atomic<T>::value_type* expected,
      typename std::atomic<T>::value_type desired ) noexcept;

(2) (since C++11)

template< class T >
bool atomic_compare_exchange_weak
    ( volatile std::atomic<T>* obj,
      typename std::atomic<T>::value_type* expected,
      typename std::atomic<T>::value_type desired ) noexcept;

(3) (since C++11)

template< class T >
bool atomic_compare_exchange_strong
    ( std::atomic<T>* obj, typename std::atomic<T>::value_type* expected,
      typename std::atomic<T>::value_type desired ) noexcept;

(4) (since C++11)

template< class T >
bool atomic_compare_exchange_strong
    ( volatile std::atomic<T>* obj,
      typename std::atomic<T>::value_type* expected,
      typename std::atomic<T>::value_type desired ) noexcept;

(5) (since C++11)

template< class T >
bool atomic_compare_exchange_weak_explicit
    ( std::atomic<T>* obj, typename std::atomic<T>::value_type* expected,
      typename std::atomic<T>::value_type desired,
      std::memory_order success, std::memory_order failure ) noexcept;

(6) (since C++11)

template< class T >
bool atomic_compare_exchange_weak_explicit
    ( volatile std::atomic<T>* obj,
      typename std::atomic<T>::value_type* expected,
      typename std::atomic<T>::value_type desired,
      std::memory_order success, std::memory_order failure ) noexcept;

(7) (since C++11)

template< class T >
bool atomic_compare_exchange_strong_explicit
    ( std::atomic<T>* obj, typename std::atomic<T>::value_type* expected,
      typename std::atomic<T>::value_type desired,
      std::memory_order success, std::memory_order failure ) noexcept;

(8) (since C++11)

template< class T >
bool atomic_compare_exchange_strong_explicit
    ( volatile std::atomic<T>* obj,
      typename std::atomic<T>::value_type* expected,
      typename std::atomic<T>::value_type desired,
      std::memory_order success, std::memory_order failure ) noexcept;

Atomically compares the object representation (until C++20) / value representation (since C++20) of the object pointed to by obj with that of the object pointed to by expected, and if those are bitwise-equal, replaces the former with desired β€” that's the read-modify-write operation, bestie. Otherwise, it loads the actual value pointed to by obj into *expected β€” that's the load operation. πŸŒ€

The memory-model tea is:

  • Overloads (1-4): the read-modify-write operation uses std::memory_order_seq_cst; the load operation uses std::memory_order_seq_cst.
  • Overloads (5-8): the read-modify-write operation uses success; the load operation uses failure.

These functions are defined in terms of member functions of std::atomic:

1,2) obj->compare_exchange_weak(*expected, desired)
3,4) obj->compare_exchange_strong(*expected, desired)
5,6) obj->compare_exchange_weak(*expected, desired, success, failure)
7,8) obj->compare_exchange_strong(*expected, desired, success, failure)
⚠️ bestie, if failure is stronger than success, or (until C++17) is one of std::memory_order_release and std::memory_order_acq_rel, the behavior is undefined. that's a hard no. πŸ’€

πŸŽ€ Parameters πŸŽ€

  • obj β€” pointer to the atomic object to test and modify.
  • expected β€” pointer to the value expected to be found in the atomic object.
  • desired β€” the value to store in the atomic object if it is as expected.
  • success β€” the memory synchronization ordering for the read-modify-write operation if the comparison succeeds.
  • failure β€” the memory synchronization ordering for the load operation if the comparison fails.

🌈 Return value 🌈

The result of the comparison: true if *obj was equal to *expected, false otherwise. iconic little boolean behavior, honestly. βœ…πŸ’”


πŸ¦‹ Notes πŸ¦‹

std::atomic_compare_exchange_weak and std::atomic_compare_exchange_weak_explicit β€” the weak versions β€” are allowed to fail spuriously, that is, act as if *obj != *expected even if they are equal. when a compare-and-exchange is in a loop, they will yield better performance on some platforms. slay for loops, lowkey. πŸ”

When a weak compare-and-exchange would require a loop and a strong one would not, the strong one is preferable unless the object representation of T may include padding bits, (until C++20) trap bits, or offers multiple object representations for the same value (e.g. floating-point NaN). In those cases, weak compare-and-exchange typically works because it quickly converges on some stable object representation. 🧚

For a union with bits that participate in the value representations of some members but not the others, compare-and-exchange might always fail because such padding bits have indeterminate values when they do not participate in the value representation of the active member. 😭

Padding bits that never participate in an object's value (since C++20) representation are ignored. noted, bestie. πŸ“


πŸ’œ Example πŸ’œ

Compare and exchange operations are often used as basic building blocks of lockfree data structures. πŸ’…

// Run this code

#include <atomic>

template<class T>
struct node
{
    T data;
    node* next;
    node(const T& data) : data(data), next(nullptr) {}
};

template<class T>
class stack
{
    std::atomic<node<T>*> head;
public:
    void push(const T& data)
    {
        node<T>* new_node = new node<T>(data);

        // put the current value of head into new_node->next
        new_node->next = head.load(std::memory_order_relaxed);

        // now make new_node the new head, but if the head
        // is no longer what's stored in new_node->next
        // (some other thread must have inserted a node just now)
        // then put that new head into new_node->next and try again
        while (!std::atomic_compare_exchange_weak_explicit(
                   &head, &new_node->next, new_node,
                   std::memory_order_release,
                   std::memory_order_relaxed))
            ; // the body of the loop is empty
        // note: the above loop is not thread-safe in at least
        // GCC prior to 4.8.3 (bug 60272), clang prior to 2014-05-05 (bug 18899)
        // MSVC prior to 2014-03-17 (bug 819819). See member function version for workaround
    }
};

int main()
{
    stack<int> s;
    s.push(1);
    s.push(2);
    s.push(3);
}

πŸ“ Defect reports πŸ“

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

  • P0558R1 β€” applied to C++11. Behavior as published: exact type match was required because T is only deduced from obj. Correct behavior: T was deduced from multiple arguments.

πŸ‘‘ See also πŸ‘‘

  • compare_exchange_weak, compare_exchange_strong β€” atomically compares the value of the atomic object with a non-atomic argument and performs atomic exchange if equal or atomic load if not. (public member function of std::atomic<T>)
  • atomic_exchange, atomic_exchange_explicit (C++11) β€” atomically replaces the value of the atomic object with a non-atomic argument and returns the old value of the atomic. (function template)
  • std::atomic_compare_exchange_weak(std::shared_ptr), std::atomic_compare_exchange_strong(std::shared_ptr) β€” specializes atomic operations for std::shared_ptr β€” deprecated in C++20, removed in C++26. (function template)
  • C documentation for atomic_compare_exchange, atomic_compare_exchange_explicit

mwah, this page is from http://cppreference.com, dated 2024.06.10 β€” kisses and atomic hugs, bye bestie πŸ’–πŸŽ€πŸ«Ά

πŸ“¦ where this page comes from