notes

Log | Files | Refs | README

rwlock_pattern.md (2778B)


      1 # RWLock Pattern
      2 
      3 The RWLock (Readers-Writer Lock) pattern is a concurrency synchronization
      4 primitive that allows multiple threads to read shared data simultaneously, but
      5 requires exclusive access for any write operation. It's ideal for scenarios
      6 where reads are frequent and writes are rare, as it avoids the unnecessary
      7 serialization that a plain Mutex would impose.
      8 
      9 ## Core Rules
     10 
     11 - Multiple readers can hold the lock at the same time — reads are non-exclusive ​
     12 
     13 - Only one writer can hold the lock at a time — writes are exclusive ​
     14 
     15 - A write lock blocks all readers and other writers until it is released ​
     16 
     17 - Once a writer is active, new readers must wait
     18 
     19 ## Rust RwLock Example
     20 
     21 Rust provides std::sync::RwLock<T> in its standard library. Here's a practical
     22 example with multiple reader threads and one writer thread:
     23 
     24 ```rust
     25 use std::sync::{Arc, RwLock};
     26 use std::thread;
     27 
     28 fn main() {
     29     // Wrap data in Arc<RwLock<T>> for shared ownership across threads
     30     let data = Arc::new(RwLock::new(0u32));
     31 
     32     // --- Writer thread: exclusive access ---
     33     let data_writer = Arc::clone(&data);
     34     let writer = thread::spawn(move || {
     35         let mut w = data_writer.write().unwrap(); // blocks until no readers/writers
     36         *w += 42;
     37         println!("Writer set value to: {}", *w);
     38     }); // write lock dropped here
     39 
     40     writer.join().unwrap();
     41 
     42     // --- Multiple reader threads: concurrent access ---
     43     let reader_handles: Vec<_> = (0..4).map(|i| {
     44         let data_reader = Arc::clone(&data);
     45         thread::spawn(move || {
     46             let r = data_reader.read().unwrap(); // multiple readers can hold this simultaneously
     47             println!("Reader {} sees value: {}", i, *r);
     48         })
     49     }).collect();
     50 
     51     for handle in reader_handles {
     52         handle.join().unwrap();
     53     }
     54 }
     55 ```
     56 
     57 ### Output (reader order may vary):
     58 
     59 ```text
     60 Writer set value to: 42
     61 Reader 0 sees value: 42
     62 Reader 2 sees value: 42
     63 Reader 1 sees value: 42
     64 Reader 3 sees value: 42
     65 ```
     66 
     67 ## When to Use vs. Mutex
     68 
     69 RwLock is only better than Mutex when you have many concurrent readers competing
     70 at the same time. For a single reader or low concurrency, an uncontended RwLock
     71 is no faster than a Mutex because readers still acquire the lock and update
     72 internal state. A good rule of thumb: if your workload is read-heavy (e.g., 90%+
     73 reads) with rare writes, RwLock gives a meaningful throughput boost. ​
     74 
     75 ## Watch Out: Lock Poisoning
     76 
     77 In Rust, if a thread panics while holding a write lock, the RwLock becomes
     78 poisoned. Subsequent calls to .read() or .write() will return an Err, which you
     79 handle via .unwrap() or .into_inner(). This is a safety feature to prevent
     80 access to potentially corrupt data.
     81 
     82 [RWLock](https://dev-doc.rust-lang.org/beta/std/sync/struct.RwLock.html)