A lock is the restroom: one key, one room, and whoever holds the key is inside. A condition variable is the waiting room next door, with a bell: a thread sleeps there until another thread rings to say that what it was waiting for has happened. The tabs follow OSTEP Chapter 28 (Locks) and Chapter 30 (Condition Variables).
Locks
one key, one room, one thread inside at a time
The restroom
Two threads, T1 and T2, both want the critical section. The flag is the Occupied sign on the door.
Lock
At the door
The restroom
The sign, in memory
flag =0
Thread 1
Thread 2
Three ways to guard the room
Pick one with the chips on the left.
Lock
Keeps one thread in?
While a thread waits
Plain flag
No. Two threads can both see vacant
spins
Test-and-set
Yes
spins, burning CPU on failed checks
Queue with park
Yes
sleeps, using no CPU, but waking takes time
The words for it
A lock gives mutual exclusion: while one thread is in the critical section, the others are kept out.
To build one, the check and the set must be atomic, one step the scheduler cannot split. Test-and-set is a hardware instruction that does exactly that.
A spin lock waits by looping. It is simple, and fine for very short critical sections on several CPUs. On one CPU it is wasteful, because the spinner holds the CPU that the lock holder needs.
A sleeping lock parks the waiter in a queue and wakes it with unpark. The next tab is about the same idea used for a different job.
Condition variables
wait outside until the bell rings
The room and the waiting rooms
A producer-consumer shelf with one slot. The key is the lock. A waiting room is a condition variable.
Version
Not in line
Awake, at the door
The room (key = lock)
consumer (Tc1, Tc2)
producer (Tp)
waiting room
The code in this version
Consumer
Producer
Lock versus condition variable
Lock
Condition variable
Picture
restroom with one key
waiting room with a bell
Answers
who may be inside now?
has what I need happened yet?
A blocked thread
waits for the holder to unlock
sleeps until another thread signals
The key while blocked
never had it
wait() hangs it up while asleep, and takes it back before returning
Used with
on its own
always a lock, and a while loop that rechecks
The bell is a hint, like a restaurant pager: by the time you reach the door, someone else may have taken the table. That is why a woken thread looks again.