# Readers and writers Our new `TicketStore` works, but its read performance is not great: there can only be one client at a time reading a specific ticket, because `Mutex` doesn't distinguish between readers and writers. We can solve the issue by using a different locking primitive: `RwLock`.\ `RwLock` stands for **read-write lock**. It allows **multiple readers** to access the data simultaneously, but only one writer at a time. `RwLock` has two methods to acquire a lock: `read` and `write`.\ `read` returns a guard that allows you to read the data, while `write` returns a guard that allows you to modify it. ```rust use std::sync::RwLock; // An integer protected by a read-write lock let lock = RwLock::new(0); // Acquire a read lock on the RwLock let guard1 = lock.read().unwrap(); // Acquire a **second** read lock // while the first one is still active let guard2 = lock.read().unwrap(); ``` ## Trade-offs On the surface, `RwLock` seems like a no-brainer: it provides a superset of the functionality of `Mutex`. Why would you ever use `Mutex` if you can use `RwLock` instead? There are two key reasons: - Locking a `RwLock` is more expensive than locking a `Mutex`.\ This is because `RwLock` has to keep track of the number of active readers and writers, while `Mutex` only has to keep track of whether the lock is held or not. This performance overhead is not an issue if there are more readers than writers, but if the workload is write-heavy `Mutex` might be a better choice. - `RwLock` can cause **writer starvation**.\ If there are always readers waiting to acquire the lock, writers might never get a chance to run.\ `RwLock` doesn't provide any guarantees about the order in which readers and writers are granted access to the lock. It depends on the policy implemented by the underlying OS, which might not be fair to writers. In our case, we can expect the workload to be read-heavy (since most clients will be reading tickets, not modifying them), so `RwLock` is a good choice.