liveBook · Manning

Spinlock

As explained in Learn Concurrent Programming with Go

A spin lock is a mutual-exclusion lock whose unsuccessful acquisition repeatedly retries while the execution remains active instead of blocking.

A spinlock is a mutual-exclusion lock for a shared resource when an execution must keep trying rather than block while another execution owns the lock. In a flight-booking workflow, reserving an entire route must treat the seat updates for all flights as one unit; atomically changing each flight’s seat count separately cannot prevent an incomplete or inconsistent booking. section 12.2 section 12.2.2

A simple spinlock stores its state in an atomic flag: 0 means free and 1 means locked. Lock acquisition repeatedly performs CompareAndSwap from 0 to 1. Only the execution whose swap succeeds owns the lock; failed attempts loop until another execution unlocks it. Unlocking atomically stores 0, making the lock available again. section 12.2.2 section 12.5

A Go implementation follows a short sequence:

  • Represent lock state with an int32 whose zero value is unlocked and whose value 1 is locked. section 12.2.2
  • Loop on atomic.CompareAndSwapInt32 until changing 0 to 1 succeeds. section 12.2.2
  • Yield with runtime.Gosched after a failed attempt so another goroutine can run and potentially release the lock. section 12.2.2
  • Release ownership with atomic.StoreInt32, changing the state back to 0. section 12.2.2

Protecting a route reservation

Give each Flight a sync.Locker and initialize it with a new spinlock. The booking operation can sort the flights, lock each one, check whether every flight has enough seats, and then update the group safely. Sorting establishes a consistent lock order for the multi-flight operation, while the spinlock supplies the Locker implementation used by each flight. section 12.2 section 12.2.2

Spinning is not free. Under high contention, waiting executions consume CPU cycles while repeatedly retrying the atomic operation. A futex-based mutex instead suspends and queues waiters until the lock becomes available, avoiding endless looping; Go mutexes likewise queue and suspend waiting goroutines through a semaphore-based implementation. section 12.0 section 12.5

A spinlock can also be extended with TryLock: make one CompareAndSwap attempt and return immediately whether it acquired the lock. The same atomic spinning approach can implement a semaphore whose Acquire waits for a permit and whose Release restores one. section 12.4

Figure 12.5 Implementing spin locks

Use the state-transition figure to trace how a failed compare-and-swap keeps retrying until an unlock changes the flag back to free. section 12.2.2

How Learn Concurrent Programming with Go covers it

How deep it goes
Works through a complete Go Locker implementation using an atomic integer, CompareAndSwap loop, scheduler yield, and atomic unlock.
Examples
Uses a multi-flight booking race and a Go SpinLock implementation with a 0/1 state flag.
What it assumes
Builds on atomic variables and CompareAndSwap while introducing the retry-loop mutex mechanism directly.
What you can do after
Build it from scratch as a Go sync.Locker and extend it with TryLock or a spinning semaphore.
How it connects
Connects atomic variables, CompareAndSwap, mutexes, futexes, semaphores, race conditions, and Go scheduling.

Also explained in

Compare how 2 books explain spinlock →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Concurrent Programming with Go. The section links point to the parts of the book it draws on.