Is a spinlock lock free?
Asked Answered
Y

1

8

I am a little bit confused about the two concepts.

definition of lock-free on wiki:

A non-blocking algorithm is lock-free if there is guaranteed system-wide progress

definition of non-blocking:

an algorithm is called non-blocking if failure or suspension of any thread cannot cause failure or suspension of another thread

I thought spinlock is lock-free, or at least non-blocking. But now I'm not sure. Because by definition, "spinlock is not lock-free" also makes sense to me. Like, if the thread holding the spinlock gets suspended, then it will cause suspension of other threads spinning outside. So, by definition, spinlock is not even non-blocking, let alone lock-free.

I'm so confused now. Can anyone explain it clearly?

Yarmouth answered 14/12, 2016 at 15:40 Comment(3)
The usual name for a spinlock that cannot fall back to a lock when spinning didn't pan out is "bug".Harmless
Yup, lock free is one of those unfortunate misnomers that means something completely different than most people think.Lungworm
@Voo: What are the most common things people think it means? wait-free? Or that it means avoiding library implementations of anything called "lock" (and they don't realize that rolling your own lock with atomics is still a lock)?Holcman
H
12

Anything that can be called a lock (exclude other threads from a critical section until the current thread unlocks) is by definition not lock-free. And yes, spinlocks are a kind of lock.

If a thread sleeps while holding the lock, no other thread can acquire it and make forward progress, and spinlocks can't prevent this. The OS can de-schedule a thread whenever it wants, even if it's in the middle of a critical section.


Note that "lock-free" isn't the same thing as "wait-free", so a lock-free algorithm can still have stuff like cmpxchg retry loops, but as long as one thread succeeds every time, it's lock free.

A wait-free algorithm can't even have that, and at most has to wait for cache misses / hardware arbitration of contended atomic operations. Wikipedia's non-blocking algorithm article defines wait-free and lock-free in more detail.


I think you're mixing up two definitions of "blocking".

I think you're talking about a spin_trylock function that tries to acquire a spinlock, and returns with an error if it fails instead of spinning. So this is non-blocking in the same sense as non-blocking I/O: fail with an error instead of waiting for resource availability.

That doesn't mean any thread in the system is making forward progress on the thing protected by the spinlock. It just means your thread can go and do something else before trying again, instead of needing to use separate threads to do something in parallel with waiting to acquire a lock.


Spinning in an infinite loop counts as blocking / not-making-progress. For this definition, there's no difference between a pure spinlock and one that (with OS assistance) sleeps until another thread unlocks.

The definition of lock-free isn't concerned with wasting CPU time / power to make room for independent work to happen.


Somewhat related: acquiring an uncontended spinlock doesn't require a system call, which means it's a "light-weight" lock. Some lock implementations always use a (relatively slow) system call even in the uncontended case. See Jeff Preshing's Always Use a Lightweight Mutex article. Also read Jeff's other posts to learn more about lock-free programming, because they're excellent. So good in fact that the [lock-free] tag wiki links to them.

Holcman answered 14/12, 2016 at 16:48 Comment(3)
@Mave: no, a cmpxchg attempt will succeed unless there's interference from another thread. Very much unlike a spin loop that's waiting for a specific value in memory. With N threads attempting cmpxchg in lockstep, at least 1 of them will succeed every iteration. It's impossible for a thread to sleep in a state that makes forward progress for other threads impossible, and livelock is also impossible. CAS retry loops are "lock-free" but not "wait-free" in formal CS terms: en.wikipedia.org/wiki/Non-blocking_algorithmHolcman
@Mave: No. If N threads attempt to take a spinlock with xchg at the same time, they can all fail, no forward progress for any thread. Therefore it's a blocking algorithm, unlike CAS retry loops where the value you're trying to CAS is derived from the previous iteration's CAS-read. (Also, this is a bad inefficient way of implementing a spinlock. Spin read-only until you see it unlocked so you don't have N threads spamming atomic RMW operations. See Locks around memory manipulation via inline assembly for a naive but not terrible x86 asm example.)Holcman
@Mave: The key point: can a thread sleep or die with memory contents left in a state that all other threads get stuck indefinitely? Yes: blocking algorithm. No: lock-free. (But not necessarily wait-free.)Holcman

© 2022 - 2024 — McMap. All rights reserved.