std::atomic...xx_LOCK_FREE(3)

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

okay bestie, welcome to the std::atomic...xx_LOCK_FREE(3) page from the C++ Standard Libary manual πŸ’… this one is all about checking whether your atomics are actually lock-free, and the vibes are very β€œtrust me, I asked the CPU.”


πŸ’– NAME πŸ’–

std::atomic_is_lock_free,ATOMIC_xxx_LOCK_FREE β€” literally std::atomic_is_lock_free,ATOMIC_xxx_LOCK_FREE 🫢


✨ Synopsis ✨

First things first: Defined in header <atomic>, and here’s the synopsis exactly as it’s written, no cap:

          Defined in header <atomic>
          template< class T >
          bool atomic_is_lock_free( const volatile std::atomic<T>* obj )
       (1) (since C++11)
          noexcept;
          template< class T >
       (2) (since C++11)
          bool atomic_is_lock_free( const std::atomic<T>* obj ) noexcept;
          #define ATOMIC_BOOL_LOCK_FREE     /* unspecified */

          #define ATOMIC_CHAR_LOCK_FREE     /* unspecified */
          #define ATOMIC_CHAR16_T_LOCK_FREE /* unspecified */
          #define ATOMIC_CHAR32_T_LOCK_FREE /* unspecified */
          #define ATOMIC_WCHAR_T_LOCK_FREE  /* unspecified */
       (3) (since C++11)
          #define ATOMIC_SHORT_LOCK_FREE    /* unspecified */
          #define ATOMIC_INT_LOCK_FREE      /* unspecified */
          #define ATOMIC_LONG_LOCK_FREE     /* unspecified */
          #define ATOMIC_LLONG_LOCK_FREE    /* unspecified */

          #define ATOMIC_POINTER_LOCK_FREE  /* unspecified */
          #define ATOMIC_CHAR8_T_LOCK_FREE  /* unspecified */
       (4) (since C++20)

So (1) and (2) are doing the runtime detective work: they determine if the atomic object pointed to by obj is implemented lock-free, as if by calling obj->is_lock_free(). And in any given program execution, the result of the lock-free query is the same for all atomic objects of the same type. Literally same answer for every atomic of that type, bestie ✨

Then (3) and (4) are the #define squad. They expand to an integer constant expression with value:

  • 0 for the built-in atomic types that are never lock-free,
  • 1 for the built-in atomic types that are sometimes lock-free,
  • 2 for the built-in atomic types that are always lock-free.

That’s the whole numeric vibe check πŸ”₯


🐚 Parameters 🐚

  • obj β€” pointer to the atomic object to examine πŸ”

🌸 Return value 🌸

true if *obj is a lock-free atomic, false otherwise. That’s it, that’s the answer 😌


πŸ¦‹ Notes πŸ¦‹

All atomic types except for std::atomic_flag may be implemented using mutexes or other locking operations, rather than using the lock-free atomic CPU instructions. Yes, sometimes your β€œatomic” is doing locks behind the scenes. It’s giving undercover πŸ’€

Atomic types are also allowed to be sometimes lock-free: for example, if only some subarchitectures support lock-free atomic access for a given type (such as the CMPXCHG16B instruction on x86-64), whether atomics are lock-free may not be known until runtime. So the answer can be a little β€œdepends on the machine’s mood,” ngl.

The C++ standard recommends (but does not require) that lock-free atomic operations are also address-free, that is, suitable for communication between processes using shared memory. Highly iconic of the standard to recommend instead of require 🫠


🌈 Example 🌈

The page says // Run this code, so here’s the code exactly:

        #include <atomic>
        #include <iostream>
        #include <utility>

        struct A { int a[100]; };
        struct B { int x, y; };

        int main()
        {
            std::atomic<A> a;
            std::atomic<B> b;
            std::cout << std::boolalpha
                      << "std::atomic<A> is lock free? "
                      << std::atomic_is_lock_free(&a) << '\n'
                      << "std::atomic<B> is lock free? "
                      << std::atomic_is_lock_free(&b) << '\n';
        }

Possible output, if your machine is feeling that way:

        std::atomic<A> is lock free? false
        std::atomic<B> is lock free? true

πŸ’€ Defect reports πŸ’€

The following behavior-changing defect reports were applied retroactively to previously published C++ standards. Not me reading the lore, but okay πŸ‘‘

  • DR LWG 3249 β€” applied to C++11. Behavior as published: atomic_is_lock_free was specified via pointers, which was ambiguous and might accept invalid pointer values. Correct behavior: specified via atomic objects.

πŸ‘€ See also πŸ‘€

  • is_lock_free β€” checks if the atomic object is lock-free (public member function of std::atomic<T>)
  • atomic_flag β€” the lock-free boolean atomic type (C++11) (class)
  • is_always_lock_free β€” indicates that the type is always lock-free [static] (C++17) (public static member constant of std::atomic<T>)
  • std::atomic_is_lock_free(std::shared_ptr) β€” specializes atomic operations for std::shared_ptr (deprecated in C++20) (removed in C++26) (function template)
  • C documentation for atomic_is_lock_free
  • C documentation for ATOMIC_*_LOCK_FREE

made with love from http://cppreference.com, version/date 2024.06.10, filed under std::atomic...xx_LOCK_FREE(3) β€” mwah πŸ’‹πŸ«Ά

πŸ“¦ where this page comes from