Synchronization

fairness and priority inversion

Fairness asks a simple question of any waiting line: does everyone eventually get served, or can someone be skipped forever? A fair lock or scheduler guarantees that every waiting thread eventually gets its turn — no thread is starved. An unfair-but-fast one may let a thread that just released a lock immediately re-grab it, which is efficient but can leave a patient waiter stuck. Most mutexes are not strictly fair by default, trading guaranteed turn-taking for speed; when you genuinely need order, you ask for a fair (FIFO) lock.

Priority inversion is a specific, notorious fairness failure that happens when threads have priorities. Picture three threads: high, medium, and low priority. The low-priority thread takes a lock. The high-priority thread then wants that same lock, so it must wait for the low thread to release it — already a mild inversion, since high is waiting on low. The disaster comes if a medium-priority thread (which does not need the lock) is runnable: the scheduler prefers medium over low, so the low-priority lock-holder never gets to run, never releases the lock, and the high-priority thread is blocked indefinitely by a medium-priority thread it has nothing to do with. Priority has been effectively inverted: medium beats high. The famous real-world case was the Mars Pathfinder lander in 1997, which kept resetting itself in space until engineers diagnosed exactly this.

The standard cure is priority inheritance: while a high-priority thread waits on a lock held by a low-priority thread, the system temporarily boosts the lock-holder to the high priority, so it can run, finish its critical section, and release the lock quickly — then drops back. (A simpler variant, the priority ceiling, raises any lock-holder to a lock's predefined ceiling priority.) These belong to real-time systems, where missing a deadline is a failure, not just a slowdown. For ordinary application code the lesson is humbler but real: locks interact with the scheduler, 'fair' and 'fast' are in tension, and a low-priority thread holding a hot lock can hurt the whole system.

Low-priority L holds lock m; high-priority H waits for m; medium-priority M (not needing m) keeps running and preempts L. L never releases m, so H is blocked by M — priority inversion. Priority inheritance temporarily raises L to H's priority so it can release m.

A medium thread can starve a high thread through a lock held by a low thread; inheritance fixes it.

Most general-purpose mutexes are not fair by default — do not assume FIFO ordering of waiters unless the documentation promises it. Priority inversion is a real-time-systems concern; in plain application code without thread priorities it usually does not arise, but unfair locks can still cause ordinary starvation.

Also called
priority inversionfairnessunbounded priority inversion優先權倒置公平性