std::atomic...ge_explicit(3)

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

πŸ’… std::atomic_exchange, std::atomic_exchange_explicit πŸ’…

okay bestie, this is the std::atomic...ge_explicit(3) page from the C++ Standard Libary manual β€” yes, "Libary" is literally how the header spells it, we contain multitudes β€” and we're about to make atomic exchange make sense. no cap. πŸ’–

✨ NAME ✨

std::atomic_exchange,std::atomic_exchange_explicit - std::atomic_exchange,std::atomic_exchange_explicit

🌸 Synopsis 🌸

Defined in header <atomic>.

template< class T >
T atomic_exchange( std::atomic<T>* obj,
                   typename std::atomic<T>::value_type desired ) noexcept; // (1) (since C++11)

template< class T >
T atomic_exchange( volatile std::atomic<T>* obj,
                   typename std::atomic<T>::value_type desired ) noexcept; // (2) (since C++11)

template< class T >
T atomic_exchange_explicit( std::atomic<T>* obj,
                            typename std::atomic<T>::value_type desired,
                            std::memory_order order ) noexcept; // (3) (since C++11)

template< class T >
T atomic_exchange_explicit( volatile std::atomic<T>* obj,
                            typename std::atomic<T>::value_type desired,
                            std::memory_order order ) noexcept; // (4) (since C++11)
  • 1,2) Atomically replaces the value pointed to by obj with the value of desired and returns the value obj held previously, as if by obj->exchange(desired).
  • 3,4) Atomically replaces the value pointed to by obj with the value of desired and returns the value obj held previously, as if by obj->exchange(desired, order).

πŸŽ€ Parameters πŸŽ€

  • obj β€” pointer to the atomic object to modify
  • desired β€” the value to store in the atomic object
  • order β€” the memory synchronization ordering

πŸ¦‹ Return value πŸ¦‹

The value held previously by the atomic object pointed to by obj.

πŸ”₯ Example πŸ”₯

A spinlock mutex can be implemented in userspace using an atomic exchange operation, similar to std::atomic_flag_test_and_set. The page literally says // Run this code, so bestie, run this code:

#include <atomic>
#include <iostream>
#include <thread>
#include <vector>

std::atomic<bool> lock(false); // holds true when locked
                               // holds false when unlocked

int new_line{1}; // the access is synchronized via atomic lock variable

void f(int n)
{
    for (int cnt = 0; cnt < 100; ++cnt)
    {
        while (std::atomic_exchange_explicit(&lock, true,
       std::memory_order_acquire))
            ; // spin until acquired
        std::cout << n << (new_line++ % 80 ? "" : "\n");
        std::atomic_store_explicit(&lock, false,
       std::memory_order_release);
    }
}

int main()
{
    std::vector<std::thread> v;
    for (int n = 0; n < 8; ++n)
        v.emplace_back(f, n);
    for (auto& t : v)
        t.join();
}

Possible output:

02222222222222222222222002222222222222222222222222222222222222222222222222222222
22222222200022222222202222211111111111110000011111111100000000000000110001111111
00011111000001111110000011111100000111000000001111111111111110000010000001001111
11011111111011111011000000000000111100000000000001111000011133333333333333333333
33333333333333333333333333333333333333333333333333333333333333333333333333333333
44444444444444444444444444444444444444444444444444444444444444444444444444444444
44444444444444444444555555555555555555555555555555555555555555555555555555555555
55555555555555555555555555555555555555556666666666666666666666666666666666666666
66666666666666666666666666666666666666666666666666666666666677777777777777777777
77777777777777777777777777777777777777777777777777777777777777777777777777777777

🩹 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 was deduced from multiple arguments. Correct behavior: T is only deduced from obj.

πŸ‘‘ See also πŸ‘‘

  • exchange β€” public member function of std::atomic<T>: atomically replaces the value of the atomic object and obtains the value held previously.
  • atomic_compare_exchange_weak (C++11) β€” function template: atomically compares the value of the atomic object with non-atomic argument and performs atomic exchange if equal or atomic load if not.
  • atomic_compare_exchange_weak_explicit (C++11) β€” function template: same compare-and-exchange vibe as above.
  • atomic_compare_exchange_strong (C++11) β€” function template: same compare-and-exchange vibe as above.
  • atomic_compare_exchange_strong_explicit (C++11) β€” function template: same compare-and-exchange vibe as above.
  • std::atomic_exchange(std::shared_ptr) β€” function template: specializes atomic operations for std::shared_ptr; deprecated in C++20, removed in C++26.
  • std::atomic_exchange_explicit(std::shared_ptr) β€” function template: specializes atomic operations for std::shared_ptr; deprecated in C++20, removed in C++26.
  • C documentation for atomic_exchange, atomic_exchange_explicit.

okay that's the whole page, bestie. source/version/date vibe check: http://cppreference.com, 2024.06.10, std::atomic...ge_explicit(3) β€” mwah πŸ’–

πŸ“¦ where this page comes from