Appearance
15. Mutex vs Semaphore
Mutex: a lock — only the thread that locked it may unlock it. Two states: locked/unlocked. Semaphore: a counter controlling how many threads may access a resource.
Two kinds of semaphore: binary (0 or 1, looks like a mutex but behaves differently) and counting (0 to N — e.g., a pool of 10 DB connections).
Core difference — ownership: a mutex has OS-enforced ownership; only the locking thread can unlock. A semaphore has none — any thread can signal() even if it never wait()ed.
Use cases: mutex → protecting shared data / critical sections. Semaphore → signaling between threads, bounding access to a resource pool, producer-consumer coordination.
Missed signals: unlocking a mutex nobody's waiting on is a no-op. sem_signal() with nobody waiting increments the count and is remembered — the next wait() proceeds immediately. A condition variable's signal() with nobody waiting is lost forever.
Priority inversion (mutex-specific): low-priority thread L holds a mutex; high-priority thread H blocks on it; medium-priority thread M preempts L — H is now indirectly waiting on M. Fixed by priority inheritance, which temporarily boosts L to H's priority. Semaphores can't use this fix — they have no ownership concept.