23

I'm experimenting with C++ atomic's std::atomic<T>::is_always_lock_free and std::atomic<T>::is_lock_free.

I wrote a simple struct A and want to know if the atomic version of A is lock-free:

#include <iostream>
#include <atomic>

using namespace std;

struct A {
  int x;
  int y;
  int z;
};

int main() {
  atomic<A> b;

  cout << boolalpha;
  cout << "b.is_always_lock_free = " << b.is_always_lock_free << endl;
  cout << "b.is_lock_free = " << b.is_lock_free() << endl;

  return 0;
}

On a x86-64 Linux, I compiled it with g++ 9.4.0 and C++17, the output is normal:

b.is_always_lock_free = false
b.is_lock_free = false

However, I also compiled it with clang++ 16.0.0 on my Mac (ARM64), the output is strange:

b.is_always_lock_free = true
b.is_lock_free = false

Why is_always_lock_free = true and is_lock_free = false? If it can always be lock-free, why b is not lock-free?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Shuai
  • 962
  • 1
  • 10
  • 21
  • 2
    And at least with clang 14 on MacOS, the type *is* in fact lock free, and loads and stores give you a simple `ldp/stp` (which is atomic on ARMv8.4). – Nate Eldredge Apr 30 '23 at 05:42
  • 7
    Just for the record on why GCC on x86-64 reports non-lock-free for types >8 bytes but <= 16, even with `-march=native` (on machines with `-mcx16`): GCC7 always avoids inlining `lock cmpxchg16b` and reports non-lock-free because it doesn't have the expected read-side scaling: readers contend with each other. https://gcc.gnu.org/ml/gcc-patches/2017-01/msg02344.html . This might perhaps change once GCC starts taking advantage of Intel's 16-byte load/store atomicity guarantees, retroactively documented in the last couple years, for Intel CPUs with the AVX feature flag. – Peter Cordes Apr 30 '23 at 10:56
  • 1
    for the record, C++20 standard in section 31.8.2 states that The return value of the `is_lock_free` member function is consistent with the value of `is_always_lock_free` for the same type. – helix Jul 26 '23 at 11:54

0 Answers0