0

This is a Test and Test-And-Set implementation of Spinlock. The following is the code for lock method.

struct ttas_lock {
  ...
  void lock() {
    for (;;) {
      if (!lock_.exchange(true, std::memory_order_acquire)) {
        break;
      }
      while (lock_.load(std::memory_order_relaxed));   // <--- spin
    }
  }
  ...
};

It spins in a while loop to check if the lock has been released before acquiring it. So that it can reduce cache coherency traffic.

However, my question is:

Since it loads lock_ with relaxed order, which doesn't sync with the release operation, i.e. unlock method, is it possible that it never loads a false value or it gets high latency before loading a false value?

for_stack
  • 21,012
  • 4
  • 35
  • 48
  • 1
    You're mixing up plain visibility of the value of the atomic itself vs. syncs-with: creating a happens-before edge implying *other* later loads will see earlier stores from the other thread. Even relaxed ops are visible promptly. Yes, spinning read-only is the correct approach. – Peter Cordes Nov 24 '22 at 10:28
  • Yes, spinning read-only is the correct approach. See also [Does cmpxchg write destination cache line on failure? If not, is it better than xchg for spinlock?](https://stackoverflow.com/q/63008857) and further discussion in my answer on [Locks around memory manipulation via inline assembly](https://stackoverflow.com/q/37241553). Also the x86 `pause` instruction is a good idea `#if defined(__x86_64__) || defined (__i386__)` – Peter Cordes Nov 24 '22 at 10:35
  • My answer on [Why set the stop flag using \`memory\_order\_seq\_cst\`, if you check it with \`memory\_order\_relaxed\`?](https://stackoverflow.com/q/70581645) is focused on whether or not `relaxed` can lead to high latency or indefinite delays; no, it can't, in any normal C++ implementation that compiles to asm for a CPU. So I think it's a duplicate even though the test-case is quite different. – Peter Cordes Nov 24 '22 at 10:57

0 Answers0