liveBook · Manning

Spinlock

As explained in C++ Concurrency in Action, Second Edition

A mutex implementation in which a waiting thread repeatedly attempts to acquire the lock rather than blocking.

A spinlock is a mutex whose waiting thread repeatedly tries to acquire it instead of making a blocking call. A simple C++ implementation uses an initially clear std::atomic_flag: lock() loops on test_and_set() until it returns false, meaning the caller has set the flag and acquired the lock. unlock() clears it. section 5.2.2 section 7.1.1

Listing 5.1. Implementation of a spinlock mutex using std::atomic_flag
class spinlock_mutex
{
    std::atomic_flag flag;
public:
    spinlock_mutex():
        flag(ATOMIC_FLAG_INIT)
    {}
    void lock()
    {
        while(flag.test_and_set(std::memory_order_acquire));
    }
    void unlock()
    {
        flag.clear(std::memory_order_release);
    }
};

The loop keeps trying while the flag was already set. The first caller to observe a clear flag exits the loop; its unlock() clears the flag for a later caller. section 5.2.2

The acquire ordering on a successful test_and_set() pairs with the release ordering on clear(). Changes to protected data made before unlock() happen before accesses by a thread that subsequently acquires the lock. This is why the loop provides more than exclusive entry: it also orders access to the data it protects. section 5.3.7

Busy-waiting makes this basic mutex a poor choice when contention is expected. Although lock() makes no blocking call, the design is not lock-free: a thread holding the mutex can prevent another thread from completing. A barrier can also use a spinning wait, yielding while it checks for a generation change; that simple approach is unsuitable for long waits. section 5.2.2 section 7.1.1 section 8.5.3

How C++ Concurrency in Action, Second Edition covers it

How deep it goes
Works through lock and unlock operations and their acquire-release ordering; warns about contention rather than developing a contention-handling strategy.
Examples
Shows a std::atomic_flag mutex and a barrier that yields while waiting for its generation to change.
What it assumes
Introduces atomic-flag locking from an initially clear flag; uses C++ class methods and threads accessing shared data.
What you can do after
Build it from scratch with std::atomic_flag and evaluate when busy-waiting or lock dependence makes it unsuitable.
How it connects
Connects atomic_flag, acquire-release ordering, mutual exclusion, lock-free progress, and barrier spin waits.

Also explained in

Compare how 2 books explain spinlock →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of C++ Concurrency in Action, Second Edition. The section links point to the parts of the book it draws on.