Skip to main content

Module 3: Concurrency & Synchronization: Case Studies

These case studies train schedule-level reasoning: races, locks, condition variables, futexes, deadlocks, and memory visibility.


Case Study 1: Lost Update In A Metrics Counter​

Scenario: Eight threads increment a shared request counter. Under load, totals are lower than expected.

Source anchor: POSIX threads and CPU atomicity explain why read-modify-write needs synchronization. See pthread_mutex_lock(3p).

Module concepts: race condition, critical section, atomicity, mutex.

Wrong Approach​

"Increment is one line, so it is one operation."

Better Approach​

Protect or avoid shared mutation:

mutex:
simple correctness

atomic:
lower overhead for simple counter

per-thread counter:
reduced contention, merge later

Tradeoff Table​

ChoiceGainCost
unsynchronized incrementminimal codeincorrect totals
mutexsimple correctnesscontention
atomic or sharded countersbetter scalabilityadded design work

Failure Mode​

Two threads read the same counter value before either write becomes visible, so one increment overwrites the other.

Project / Capstone Connection​

Use this in observability, rate-limiting, or analytics features where shared counters look simple but sit on hot concurrent paths.

Required Artifact​

Draw the interleaving that loses one increment and write two fixes.


Case Study 2: Condition Variable Wait Without While Loop​

Scenario: A worker waits for a queue to be non-empty using if, wakes spuriously or after another worker consumes the item, and pops from an empty queue.

Source anchor: man7 pthread_cond_init(3) explains condition variables and their associated mutex discipline.

Module concepts: condition variable, predicate, spurious wakeup, mutex.

Wrong Approach​

Use if queue_empty wait().

Better Approach​

Wait in a loop:

pthread_mutex_lock(&m);
while (queue_empty(q)) {
pthread_cond_wait(&cv, &m);
}
item = pop(q);
pthread_mutex_unlock(&m);

Tradeoff Table​

ChoiceGainCost
if before waitshorter codebroken on wake races
while on predicatecorrect synchronizationslightly more ceremony
semaphore-only redesignsimpler queue contract in some casesdifferent primitive

Failure Mode​

The thread wakes without the queue predicate being true, or another consumer wins the race first, so the awakened worker reads invalid state.

Project / Capstone Connection​

This appears in producer-consumer queues, job schedulers, and background workers that capstone teams often build around shared buffers.

Required Artifact​

Write the producer-consumer schedule that breaks if and the corrected loop.


Case Study 3: Futex Makes Uncontended Locks Cheap​

Scenario: A learner assumes every mutex lock enters the kernel. Profiling shows uncontended locks are mostly user-space and only contended paths use kernel help.

Source anchor: futex(2) documents fast user-space locking with kernel assistance on contention.

Module concepts: futex, user-space fast path, kernel wait queue, contention.

Wrong Approach​

"Locks are always syscalls."

Better Approach​

Understand the fast/slow path:

uncontended:
atomic user-space state change

contended:
futex wait/wake through kernel

Tradeoff Table​

ChoiceGainCost
assume every lock traps to kerneleasy mental modelwrong performance diagnosis
understand futex fast pathaccurate profilingmore systems detail
redesign to reduce contentionfewer slow pathsimplementation effort

Failure Mode​

Teams misread profiling data, optimize the wrong layer, and miss that contention rather than lock existence is what drives kernel involvement.

Project / Capstone Connection​

Use this when performance-tuning threaded services or runtimes where lock behavior shows up in profilers and needs correct interpretation.

Required Artifact​

Draw mutex fast path and slow path with the futex operation point.


Case Study 4: Deadlock In Two-Resource Transfer​

Scenario: Thread A locks account 1 then 2. Thread B locks account 2 then 1. Both wait forever.

Source anchor: POSIX mutex docs and classic OS deadlock conditions apply. See pthread_mutex_lock(3p).

Module concepts: deadlock, circular wait, lock ordering, wait-for graph.

Wrong Approach​

"Deadlocks are rare; retry the program."

Better Approach​

Use deterministic lock order:

lock min(account_id)
lock max(account_id)
perform transfer
unlock reverse order

Tradeoff Table​

ChoiceGainCost
ad hoc lock ordersimple local codedeadlock risk
global lock orderingeliminates circular waitcoordination across code
coarse single lockeasy reasoningless parallelism

Failure Mode​

Each thread holds one resource while waiting on the other, forming a circular wait that no scheduler decision can resolve.

Project / Capstone Connection​

This maps to banking demos, inventory systems, or any capstone that transfers state between two shared entities.

Required Artifact​

Draw the wait-for graph and rewrite the lock acquisition rule.


Case Study 5: Spinlock Used Around Blocking I/O​

Scenario: A low-level service uses a spinlock while writing logs to disk. Under I/O delay, CPU burns while threads spin.

Source anchor: Linux synchronization primitives and OS scheduling distinguish spin waiting from blocking. Use futex(2) as the contrast point.

Module concepts: spinlock, blocking mutex, critical-section length, I/O.

Wrong Approach​

"Spinlocks are faster."

Better Approach​

Use spin only for tiny non-blocking critical sections:

short CPU-only state:
spin may fit

I/O or unknown wait:
blocking mutex/queue

Tradeoff Table​

ChoiceGainCost
spin around blocking I/Osimple primitive reusewasted CPU
blocking mutexscheduler-friendly waitcontext-switch overhead
queue and async loggingdecoupled latencymore system design

Failure Mode​

Threads burn CPU waiting for a lock that cannot be released quickly because the lock holder is blocked on disk I/O.

Project / Capstone Connection​

Apply this to logging, persistence, or adapter layers where a capstone service mixes shared state protection with potentially slow external operations.

Required Artifact​

Write a lock-choice table for five critical sections in a service.


Source Map​

SourceUse it for
pthread_mutex_lock(3p)mutex behavior
pthread condition variablescondition variables and mutex association
futex(2)user-space fast path and kernel blocking

Completion Standard​

  • At least three artifacts are completed.
  • At least one artifact includes a breaking interleaving.
  • At least one artifact includes a wait-for graph.