A producer puts items into a shared buffer and consumers take them out. Each side has to wait when the buffer is wrong for it: full for the producer, empty for the consumer. The tabs follow the four implementations in OSTEP Chapter 30 in order: two that are broken in different ways, then two that work. The line labels p1 to p6 and c1 to c6 are the ones the book uses in its traces.
Keyboard: ← → to step, Space to play or pause.
Code and traces follow OSTEP, Chapter 30, Condition Variables. CV means condition variable.