c++20 - Why doesn't C++ compare_exchange allow stronger consistency for fail than success - Stack Overflow

admin2025-04-25  1

I've got a lock-like structure that lets threads block until the exclusive lock is free. It's not relevant to my question, but in case you are thinking "Just don't do that," the blocking is actually useful for two different derived classes: 1) traditional reader-writer locks wait for the exclusive lock to be released when attempting the shared lock (which inhibits further exclusive lockers), and 2) RCU-like reader locks allow coroutines to read shared data until they are suspended (because the exclusive lock waits for each thread in a thread pool to have passed through a quiescent period).

The code looks like this:

struct LockBase {
  static constexpr int kUnlocked = 0;
  static constexpr int kLocked = 1;
  static constexpr int kLockedWantNotify = 2;
  std::atomic_int status_{kUnlocked};

  // ...

  void unlock() noexcept
  {
    if (status_.exchange(kUnlocked) == kLockedWantNotify)
      status_.notify_all();
  }

  void block_until_unlocked() noexcept
  {
    for (;;) {
      int prev = status_.load(std::memory_order_acquire);
      if (prev == kLocked)
        status_pare_exchange_weak(
            prev, kLockedWantNotify,
            std::memory_order_relaxed,  // success ordering
            std::memory_order_acquire); // failure ordering
      if (prev == kUnlocked)
        return;
      status_.wait(kLockedWantNotify);
    }
  }
};

The rationale here is that if the compare and exchange fails and the previous value has changed to unlocked, then we are done, so we need acquire semantics to synchronize with the thread that released the lock. On the other hand, if the compare and exchange succeeds, then we are just going to go to sleep in a futex, so relaxed memory order is fine.

Unfortunately, certain versions of clang complain that the failure consistency can't be stronger than the success consistency:

/usr/include/c++/14/bits/atomic_base.h:536:43: error: failure memory model ‘memory_order_acquire’ cannot be stronger than success memory model ‘memory_order_relaxed’ for ‘bool __atomic_compare_exchange_4(volatile void*, void*, unsigned int, bool, int, int)’ [-Werror=invalid-memory-model]
  536 |         return __atomic_compare_exchange_n(&_M_i, &__i1, __i2, 1,
      |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~
  537 |                                            int(__m1), int(__m2));
      |                                            ~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/14/bits/atomic_base.h:536:43: note: valid models are 'memory_order_relaxed'

My questions: Is clang right about C++ prohibiting my code? Why would C++ have such a restriction? I mean if the hardware doesn't support it, the compiler could always safely promote the failure consistency to be the same as the success consistency. It's bizarre to be paternalistic about a potentially useful edge case in a language facility (relaxed atomics) that is otherwise designed to inflict maximum undefined behavior on all but the most expert programmers.

转载请注明原文地址:http://anycun.com/QandA/1745596233a90954.html