CXX and atomic instructions
-
Topic author - Active Contributor
- Posts: 43
- Joined: Sat Sep 02, 2023 1:31 pm
- Reputation: 0
- Location: Colorado Springs, CO, USA
- Status: Offline
CXX and atomic instructions
What atomic instructions are available to the C++ compiler on x86? I've been using __ATOMIC_EXCH_LONG, __CMP_SWAP_LONG_ACQ, and similar.
Re: CXX and atomic instructions
Use std::atomic (C++11). I figured this one out while looking at libuv, which is written in C and uses <stdatomic.h> from C11, which isn't present in the VMS C RTL.
It's a total hack, but I discovered that I could compile the libuv code as C++ (after adding some casts and other needed changes), change the include to <atomic>, and change "_Atomic int" to "atomic_int". The Clang version of the C++ header file includes both the C++ atomic<> class and all the C functions in <stdatomic.h> (in std:: or you can use the namespace).
https://en.cppreference.com/w/cpp/header/stdatomic.h
https://en.cppreference.com/w/cpp/atomic/atomic
Typical uses of the C API in libuv:
One thing I noticed right away in the VMS version of the header file (due to color syntax highlighting) is that the first 550 lines are commented out, and the actual implementation starts below that. I was worried there might be something not implemented yet, but it looks like it's all there, below the commented-out block.
It's a total hack, but I discovered that I could compile the libuv code as C++ (after adding some casts and other needed changes), change the include to <atomic>, and change "_Atomic int" to "atomic_int". The Clang version of the C++ header file includes both the C++ atomic<> class and all the C functions in <stdatomic.h> (in std:: or you can use the namespace).
https://en.cppreference.com/w/cpp/header/stdatomic.h
https://en.cppreference.com/w/cpp/atomic/atomic
Typical uses of the C API in libuv:
Code: Select all
version = atomic_load_explicit(&cached_version, memory_order_relaxed);
atomic_store_explicit(&cached_version, version, memory_order_relaxed);
atomic_fetch_add(busy, 1);
atomic_fetch_add(busy, -1);
atomic_exchange(pending, 1);
Last edited by jhamby on Wed Nov 08, 2023 3:48 pm, edited 1 time in total.
Re: CXX and atomic instructions
I learned a few details about std::atomic on OpenVMS that may be of interest. std::atomic<> is typically lock-free for types that are atomic in hardware (up to 64 bits on x86, if suitably aligned), but it also supports larger types with a hidden lock.
Sadly, the VMS runtime support is currently missing for those types. There's an .is_lock_free() method in C++11 and a const member is_always_lock_free (for compile-time testing) added in C++17. Trying them on OpenVMS, you can't use .is_lock_free() or "is_always_lock_free" on non-primitive types because libcxx is missing __atomic_is_lock_free. They both return true for bool, pointers, etc. (you need /stand=cxx17 to see is_always_lock_free).
Similarly, if you try to load or store to a non-lock-free atomic type, you get an undefined __atomic_load or __atomic_store. I tried to use them for a pointer type in the project I'm working on, and I discovered some limitations of this C++ type, namely that it doesn't have a simple constructor and turns containing structs into non-POD types, which means C-style code doing stuff like putting the struct inside a union or using a macro to get the offsetof() a member or to find the containing struct given a pointer to an inner one gives a compiler warning about being a non-POD type.
So my "just use this" advice turned out to be full of limitations. The best talk I've seen on using C++ atomics is Fedor Pikus's 2017 CppCon talk. Highly recommended. https://youtu.be/ZQFzMfHIxng?si=CpD68zQw3WjLszAK
Sadly, the VMS runtime support is currently missing for those types. There's an .is_lock_free() method in C++11 and a const member is_always_lock_free (for compile-time testing) added in C++17. Trying them on OpenVMS, you can't use .is_lock_free() or "is_always_lock_free" on non-primitive types because libcxx is missing __atomic_is_lock_free. They both return true for bool, pointers, etc. (you need /stand=cxx17 to see is_always_lock_free).
Similarly, if you try to load or store to a non-lock-free atomic type, you get an undefined __atomic_load or __atomic_store. I tried to use them for a pointer type in the project I'm working on, and I discovered some limitations of this C++ type, namely that it doesn't have a simple constructor and turns containing structs into non-POD types, which means C-style code doing stuff like putting the struct inside a union or using a macro to get the offsetof() a member or to find the containing struct given a pointer to an inner one gives a compiler warning about being a non-POD type.
So my "just use this" advice turned out to be full of limitations. The best talk I've seen on using C++ atomics is Fedor Pikus's 2017 CppCon talk. Highly recommended. https://youtu.be/ZQFzMfHIxng?si=CpD68zQw3WjLszAK
Last edited by jhamby on Sun Nov 12, 2023 4:50 pm, edited 1 time in total.
Re: CXX and atomic instructions
I'll have somebody look into this.