Imagine a library catalog. Many users can read it together, but librarians must update it alone. The reader-writer pattern applies this idea to shared data: readers may proceed concurrently, while writers receive exclusive access. section 9.9
The coordination rules are simple:
- Allow any number of readers to access unchanged shared data simultaneously. section 9.9
- Allow only one writer at a time. section 9.9
- Block all readers while a writer updates the data. section 9.9
# Chapter 9/reader_writer/rwlock.py
from threading import Lock
class RWLock:
def __init__(self) -> None:
self.readers = 0
self.read_lock = Lock()
self.write_lock = Lock()
def acquire_read(self) -> None: #1
self.read_lock.acquire() #1
self.readers += 1 #1
if self.readers == 1: #1
self.write_lock.acquire() #1
self.read_lock.release() #1
def release_read(self) -> None: #2
assert self.readers >= 1 #2
self.read_lock.acquire() #2
self.readers -= 1 #2
if self.readers == 0: #2
self.write_lock.release() #2
self.read_lock.release() #2
def acquire_write(self) -> None: #3
self.write_lock.acquire() #3
def release_write(self) -> None: #4
self.write_lock.release() #4
The Python implementation counts active readers, protects that count with one lock, and uses another lock to exclude writers while readers are present. section 9.9
Users and librarians
Several User threads can print the same counter value together. A Librarian thread waits for readers, increments the counter, and then releases the write lock. This avoids conflicting read/write and write/write interleavings while avoiding unnecessary serialization of readers. section 9.9


