logoalt Hacker News

gavinlillyyesterday at 11:28 PM1 replyview on HN

If contention is expected, would it be better to first perform a relaxed read before the exchange? For example:

  auto lock() noexcept -> void {
      auto backoff = 1;
      do {
          while (locked_.load(std::memory_order_relaxed)) {
              for (auto i = 0; i < backoff; ++i) _mm_pause();
              backoff = backoff < 64 ? backoff << 1 : 64;
          }
      } while (locked_.exchange(true, std::memory_order_acquire);
  }

Replies

nlyyesterday at 11:37 PM

If you're expecting heavy contention, and there's no risk of any of the threads being descheduled, then FIFO spinlocks are probably best.

In a FIFO threads register themselves into a linked list, and the thread calling unlock() directly wakes the next. It's possible to have e.g. 20 threads in this case all spinning on their own cache lines (their private node), rather than a shared one (the lock head).

This can be coherence protocol optimal.

A dumb test and set spinlock, or variant thereof, is going to degrade quickly as all the cores are spinning on the same cacheline causing a lot of coherence traffic between cores (transitions between shared, exclusive and modified states)