Classic Synchronization Problems & Concurrent Programming

the readers-writers problem

Imagine a public reference book on a library table that anyone may read. Many people can crowd around and read it at the same time with no trouble — reading does not change anything. But suppose a librarian needs to glue in a correction. While that edit is happening, nobody should be reading, because they might see half-old, half-new text, and no second editor should be writing at the same time either. The readers-writers problem captures this exact asymmetry for shared data: any number of readers may access it simultaneously, but a writer needs exclusive access — alone, with all readers and other writers kept out.

This is more permissive than a plain mutex, which would force readers to take turns even though concurrent reads are perfectly safe. The standard solution uses a reader-count protected by its own small lock, plus one writer lock. The first reader to arrive grabs the writer lock (locking writers out), later readers just bump the count and walk in, and the last reader to leave releases the writer lock. A writer simply takes the writer lock for itself. A real lock primitive built on this idea is the read-write lock (in pthreads, pthread_rwlock_t): callers ask for either a shared read lock or an exclusive write lock.

The catch — and the reason this is a teaching problem, not just a recipe — is policy. The simple solution above is reader-preference: as long as readers keep streaming in, the writer lock is never free, so a waiting writer can be starved forever. Flip the rule to writer-preference and you fix that, but now a steady flow of writers can starve the readers. Real systems usually want a fair version that bounds how long either side waits. So the readers-writers problem is less about one answer and more about consciously choosing a fairness policy and living with its trade-offs.

Reader entry: lock(countMutex); if (++readers == 1) wait(writeLock); unlock(countMutex). Reader exit: lock(countMutex); if (--readers == 0) signal(writeLock); unlock(countMutex). Writer: wait(writeLock) ... signal(writeLock).

The classic reader-preference solution — fast for read-heavy data, but a writer can starve while readers keep arriving.

A read-write lock only pays off when reads vastly outnumber writes and each critical section is long enough. For short or balanced workloads its extra bookkeeping often makes it slower than a plain mutex.

Also called
讀寫問題shared-exclusive locking