Different Locks
When we need some arbitration on the concurrent read/write requests, the lock is introduced. It reorders these requests as they run in series, which limits the commutativity of these operators.
However, this constraint is not fit for all scenarios, especially when we need concurrency and consistency.
One Writer and One Reader
Not all one-writer-one-reader scenarios require a mutex-like lock. If threads only need to do hand-shake communication (e.g., signaling completion or publishing a flag), volatile memory accesses, atomic operations with proper memory ordering, or a simple CAS are sufficient. A full lock is unnecessary when the shared state is small enough to be updated atomically and no multi-step invariant needs to be protected.
When the shared data does involve a critical section (e.g., updating multiple fields that must remain consistent), a simple exclusive lock is enough. To choose between a CAS spinlock or mutex, we need benchmarks to measure the critical section time usage, but mostly, mutex is easier to use while maintaining the correctness.
Further, with sufficient knowledge of the running state, we can avoid locking altogether through data sharding and isolation, or guarantee progress under contention with wait-free data structures.
One Writer and Multiple Readers
This is a common shared-data access pattern, which also appears in some scenarios of message queue. A plain mutex works but is wasteful here - readers would block each other even though concurrent reads are safe. The Read-Write-Lock addresses this by distinguishing shared (read) and exclusive (write) access.
It tracks reader count so that multiple readers can proceed in parallel, while the writer must wait for exclusive access. Dirty reads are prevented by the lock, and write conflicts are absent because there is only one writer.
Multiple Writers and One Reader
This is a rare case in practice - writers usually need to read before writing, which makes them readers too and turns this into the multi-writer-multi-reader case. Even if writers are all “blind”, the system still needs to maintain order arbitration, both physically (e.g. temporal order) and logically (e.g. update order on the same key).
Multiple Writers and Multiple Readers
This is the most common case in both local and distributed systems. A mutex is the straightforward solution, but it serializes all access.
The one-writer-multi-readers pattern hints at a better approach: if each reader can see a consistent snapshot without blocking writers, we gain concurrency without sacrificing correctness. Generalizing this idea gives us MVCC - writers create new versions while readers operate on immutable snapshots, achieving better concurrency than a mutex and far less complexity than full wait-free data structures.