Skip to main content

parking_lot/
rwlock.rs

1use crate::raw_rwlock::RawRwLock;
2
3/// A reader-writer lock.
4///
5/// This type of lock allows a number of readers or at most one writer at any
6/// point in time. The write portion of this lock typically allows modification
7/// of the underlying data (exclusive access) and the read portion of this lock
8/// typically allows for read-only access (shared access).
9///
10/// This lock uses a task-fair locking policy which generally gives waiting
11/// writers priority over new readers. This means that readers trying to acquire
12/// the lock will block even if the lock is unlocked when there are writers
13/// waiting to acquire the lock. Because of this, attempts to recursively acquire
14/// a read lock within a single thread may result in a deadlock.
15///
16/// Use [`RecursiveRwLock`](crate::RecursiveRwLock) instead if recursive read
17/// locking is required.
18///
19/// The type parameter `T` represents the data that this lock protects. It is
20/// required that `T` satisfies `Send` to be shared across threads and `Sync` to
21/// allow concurrent access through readers. The RAII guards returned from the
22/// locking methods implement `Deref` (and `DerefMut` for the `write` methods)
23/// to allow access to the contents of the lock.
24///
25/// # Fairness
26///
27/// This rwlock uses unfair unlocking by default, which allows newly arriving
28/// threads to acquire the lock before a waiting thread and generally improves
29/// throughput. This can starve waiting threads.
30///
31/// Fair unlocking can be requested explicitly by calling
32/// `RwLockReadGuard::unlock_fair` or `RwLockWriteGuard::unlock_fair` instead of
33/// simply dropping the guard. A fair unlock gives waiting threads priority over
34/// newly arriving threads.
35///
36/// # Differences from the standard library `RwLock`
37///
38/// - Task-fair locking policy instead of an unspecified platform default.
39/// - No poisoning, the lock is released normally on panic.
40/// - Only requires one word of lock state.
41/// - Supports upgradable read locks and atomic upgrades to write locks.
42/// - Supports locking with a timeout.
43/// - Allows raw locking & unlocking without a guard.
44/// - Supports explicit fair unlocking by calling
45///   `RwLockReadGuard::unlock_fair` and `RwLockWriteGuard::unlock_fair`.
46///
47/// # Examples
48///
49/// ```
50/// use parking_lot::RwLock;
51///
52/// let lock = RwLock::new(5);
53///
54/// // Multiple readers can access the data concurrently.
55/// std::thread::scope(|scope| {
56///     for _ in 0..3 {
57///         scope.spawn(|| {
58///             let reader = lock.read();
59///             assert_eq!(*reader, 5);
60///         });
61///     }
62/// });
63///
64/// // All reader threads have finished. Only one write lock may be held.
65/// {
66///     let mut writer = lock.write();
67///     *writer += 1;
68///     assert_eq!(*writer, 6);
69/// } // Write lock is released.
70/// ```
71pub type RwLock<T> = lock_api::RwLock<RawRwLock, T>;
72
73/// An RAII guard which releases shared read access when dropped.
74pub type RwLockReadGuard<'a, T> = lock_api::RwLockReadGuard<'a, RawRwLock, T>;
75
76/// An RAII guard which releases exclusive write access when dropped.
77pub type RwLockWriteGuard<'a, T> = lock_api::RwLockWriteGuard<'a, RawRwLock, T>;
78
79/// An RAII read lock guard returned by [`RwLockReadGuard::map`], which can point to a
80/// subfield of the protected data.
81///
82/// The main difference between `MappedRwLockReadGuard` and `RwLockReadGuard` is that the
83/// former doesn't support temporarily unlocking and re-locking, since that
84/// could introduce soundness issues if the locked object is modified by another
85/// thread.
86pub type MappedRwLockReadGuard<'a, T> = lock_api::MappedRwLockReadGuard<'a, RawRwLock, T>;
87
88/// An RAII write lock guard returned by [`RwLockWriteGuard::map`], which can point to a
89/// subfield of the protected data.
90///
91/// The main difference between `MappedRwLockWriteGuard` and `RwLockWriteGuard` is that the
92/// former doesn't support temporarily unlocking and re-locking, since that
93/// could introduce soundness issues if the locked object is modified by another
94/// thread.
95pub type MappedRwLockWriteGuard<'a, T> = lock_api::MappedRwLockWriteGuard<'a, RawRwLock, T>;
96
97/// An RAII guard which releases upgradable read access when dropped.
98pub type RwLockUpgradableReadGuard<'a, T> = lock_api::RwLockUpgradableReadGuard<'a, RawRwLock, T>;
99
100#[cfg(test)]
101mod tests {
102    use crate::{RwLock, RwLockUpgradableReadGuard, RwLockWriteGuard};
103    use rand::RngExt;
104    use std::sync::Arc;
105    use std::sync::atomic::{AtomicUsize, Ordering};
106    use std::thread;
107
108    #[cfg(feature = "serde")]
109    use postcard::{from_bytes, to_stdvec};
110
111    #[derive(Eq, PartialEq, Debug)]
112    struct NonCopy(i32);
113
114    #[test]
115    fn smoke() {
116        let l = RwLock::new(());
117        drop(l.read());
118        drop(l.write());
119        drop(l.upgradable_read());
120        drop((l.read(), l.read()));
121        drop((l.read(), l.upgradable_read()));
122        drop(l.write());
123    }
124
125    #[test]
126    fn frob() {
127        const N: u32 = 10;
128        const M: u32 = if cfg!(miri) { 100 } else { 1000 };
129
130        let r = Arc::new(RwLock::new(()));
131
132        let mut threads = Vec::new();
133        for _ in 0..N {
134            let r = r.clone();
135            threads.push(thread::spawn(move || {
136                let mut rng = rand::rng();
137                for _ in 0..M {
138                    if rng.random_bool(1.0 / N as f64) {
139                        drop(r.write());
140                    } else {
141                        drop(r.read());
142                    }
143                }
144            }));
145        }
146        for thread in threads {
147            thread.join().unwrap();
148        }
149    }
150
151    #[test]
152    fn test_rw_arc_no_poison_wr() {
153        let arc = Arc::new(RwLock::new(1));
154        let arc2 = arc.clone();
155        let _: Result<(), _> = thread::spawn(move || {
156            let _lock = arc2.write();
157            panic!();
158        })
159        .join();
160        let lock = arc.read();
161        assert_eq!(*lock, 1);
162    }
163
164    #[test]
165    fn test_rw_arc_no_poison_ww() {
166        let arc = Arc::new(RwLock::new(1));
167        let arc2 = arc.clone();
168        let _: Result<(), _> = thread::spawn(move || {
169            let _lock = arc2.write();
170            panic!();
171        })
172        .join();
173        let lock = arc.write();
174        assert_eq!(*lock, 1);
175    }
176
177    #[test]
178    fn test_rw_arc_no_poison_rr() {
179        let arc = Arc::new(RwLock::new(1));
180        let arc2 = arc.clone();
181        let _: Result<(), _> = thread::spawn(move || {
182            let _lock = arc2.read();
183            panic!();
184        })
185        .join();
186        let lock = arc.read();
187        assert_eq!(*lock, 1);
188    }
189
190    #[test]
191    fn test_rw_arc_no_poison_rw() {
192        let arc = Arc::new(RwLock::new(1));
193        let arc2 = arc.clone();
194        let _: Result<(), _> = thread::spawn(move || {
195            let _lock = arc2.read();
196            panic!()
197        })
198        .join();
199        let lock = arc.write();
200        assert_eq!(*lock, 1);
201    }
202
203    #[test]
204    fn test_ruw_arc() {
205        let arc = Arc::new(RwLock::new(0));
206        let arc2 = arc.clone();
207
208        let writer = thread::spawn(move || {
209            for _ in 0..10 {
210                let mut lock = arc2.write();
211                let tmp = *lock;
212                *lock = -1;
213                thread::yield_now();
214                *lock = tmp + 1;
215            }
216        });
217
218        let mut children = Vec::new();
219
220        // Upgradable readers try to catch the writer in the act and also
221        // try to touch the value
222        for _ in 0..5 {
223            let arc3 = arc.clone();
224            children.push(thread::spawn(move || {
225                let lock = arc3.upgradable_read();
226                let tmp = *lock;
227                assert!(tmp >= 0);
228                thread::yield_now();
229                let mut lock = RwLockUpgradableReadGuard::upgrade(lock);
230                assert_eq!(tmp, *lock);
231                *lock = -1;
232                thread::yield_now();
233                *lock = tmp + 1;
234            }));
235        }
236
237        // Readers try to catch the writers in the act
238        for _ in 0..5 {
239            let arc4 = arc.clone();
240            children.push(thread::spawn(move || {
241                let lock = arc4.read();
242                assert!(*lock >= 0);
243            }));
244        }
245
246        // Wait for children to pass their asserts
247        for r in children {
248            assert!(r.join().is_ok());
249        }
250
251        // Wait for writer to finish
252        writer.join().unwrap();
253        let lock = arc.read();
254        assert_eq!(*lock, 15);
255    }
256
257    #[test]
258    fn test_rw_arc() {
259        let arc = Arc::new(RwLock::new(0));
260        let arc2 = arc.clone();
261
262        let writer = thread::spawn(move || {
263            let mut lock = arc2.write();
264            for _ in 0..10 {
265                let tmp = *lock;
266                *lock = -1;
267                thread::yield_now();
268                *lock = tmp + 1;
269            }
270        });
271
272        // Readers try to catch the writer in the act
273        let mut children = Vec::new();
274        for _ in 0..5 {
275            let arc3 = arc.clone();
276            children.push(thread::spawn(move || {
277                let lock = arc3.read();
278                assert!(*lock >= 0);
279            }));
280        }
281
282        // Wait for children to pass their asserts
283        for r in children {
284            assert!(r.join().is_ok());
285        }
286
287        // Wait for writer to finish
288        writer.join().unwrap();
289        let lock = arc.read();
290        assert_eq!(*lock, 10);
291    }
292
293    #[test]
294    fn test_rw_arc_access_in_unwind() {
295        let arc = Arc::new(RwLock::new(1));
296        let arc2 = arc.clone();
297        let _ = thread::spawn(move || {
298            struct Unwinder {
299                i: Arc<RwLock<isize>>,
300            }
301            impl Drop for Unwinder {
302                fn drop(&mut self) {
303                    let mut lock = self.i.write();
304                    *lock += 1;
305                }
306            }
307            let _u = Unwinder { i: arc2 };
308            panic!();
309        })
310        .join();
311        let lock = arc.read();
312        assert_eq!(*lock, 2);
313    }
314
315    #[test]
316    fn test_rwlock_unsized() {
317        let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]);
318        {
319            let b = &mut *rw.write();
320            b[0] = 4;
321            b[2] = 5;
322        }
323        let comp: &[i32] = &[4, 2, 5];
324        assert_eq!(&*rw.read(), comp);
325    }
326
327    #[test]
328    fn test_read_with_waiting_writer() {
329        let lock = Arc::new(RwLock::new(()));
330        let reader = lock.read();
331
332        let lock2 = Arc::clone(&lock);
333        let writer = thread::spawn(move || drop(lock2.write()));
334        while !unsafe { lock.raw() }.has_parked_threads() {
335            thread::yield_now();
336        }
337
338        // A waiting writer blocks new readers even though no writer holds the lock.
339        assert!(lock.try_read().is_none());
340
341        drop(reader);
342        writer.join().unwrap();
343    }
344
345    #[test]
346    fn test_rwlock_try_read() {
347        let lock = RwLock::new(0isize);
348        {
349            let read_guard = lock.read();
350
351            let read_result = lock.try_read();
352            assert!(
353                read_result.is_some(),
354                "try_read should succeed while read_guard is in scope"
355            );
356
357            drop(read_guard);
358        }
359        {
360            let upgrade_guard = lock.upgradable_read();
361
362            let read_result = lock.try_read();
363            assert!(
364                read_result.is_some(),
365                "try_read should succeed while upgrade_guard is in scope"
366            );
367
368            drop(upgrade_guard);
369        }
370        {
371            let write_guard = lock.write();
372
373            let read_result = lock.try_read();
374            assert!(
375                read_result.is_none(),
376                "try_read should fail while write_guard is in scope"
377            );
378
379            drop(write_guard);
380        }
381    }
382
383    #[test]
384    fn test_rwlock_try_write() {
385        let lock = RwLock::new(0isize);
386        {
387            let read_guard = lock.read();
388
389            let write_result = lock.try_write();
390            assert!(
391                write_result.is_none(),
392                "try_write should fail while read_guard is in scope"
393            );
394            assert!(lock.is_locked());
395            assert!(!lock.is_locked_exclusive());
396
397            drop(read_guard);
398        }
399        {
400            let upgrade_guard = lock.upgradable_read();
401
402            let write_result = lock.try_write();
403            assert!(
404                write_result.is_none(),
405                "try_write should fail while upgrade_guard is in scope"
406            );
407            assert!(lock.is_locked());
408            assert!(!lock.is_locked_exclusive());
409
410            drop(upgrade_guard);
411        }
412        {
413            let write_guard = lock.write();
414
415            let write_result = lock.try_write();
416            assert!(
417                write_result.is_none(),
418                "try_write should fail while write_guard is in scope"
419            );
420            assert!(lock.is_locked());
421            assert!(lock.is_locked_exclusive());
422
423            drop(write_guard);
424        }
425    }
426
427    #[test]
428    fn test_rwlock_try_upgrade() {
429        let lock = RwLock::new(0isize);
430        {
431            let read_guard = lock.read();
432
433            let upgrade_result = lock.try_upgradable_read();
434            assert!(
435                upgrade_result.is_some(),
436                "try_upgradable_read should succeed while read_guard is in scope"
437            );
438
439            drop(read_guard);
440        }
441        {
442            let upgrade_guard = lock.upgradable_read();
443
444            let upgrade_result = lock.try_upgradable_read();
445            assert!(
446                upgrade_result.is_none(),
447                "try_upgradable_read should fail while upgrade_guard is in scope"
448            );
449
450            drop(upgrade_guard);
451        }
452        {
453            let write_guard = lock.write();
454
455            let upgrade_result = lock.try_upgradable_read();
456            assert!(
457                upgrade_result.is_none(),
458                "try_upgradable should fail while write_guard is in scope"
459            );
460
461            drop(write_guard);
462        }
463    }
464
465    #[test]
466    fn test_into_inner() {
467        let m = RwLock::new(NonCopy(10));
468        assert_eq!(m.into_inner(), NonCopy(10));
469    }
470
471    #[test]
472    fn test_into_inner_drop() {
473        struct Foo(Arc<AtomicUsize>);
474        impl Drop for Foo {
475            fn drop(&mut self) {
476                self.0.fetch_add(1, Ordering::SeqCst);
477            }
478        }
479        let num_drops = Arc::new(AtomicUsize::new(0));
480        let m = RwLock::new(Foo(num_drops.clone()));
481        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
482        {
483            let _inner = m.into_inner();
484            assert_eq!(num_drops.load(Ordering::SeqCst), 0);
485        }
486        assert_eq!(num_drops.load(Ordering::SeqCst), 1);
487    }
488
489    #[test]
490    fn test_get_mut() {
491        let mut m = RwLock::new(NonCopy(10));
492        *m.get_mut() = NonCopy(20);
493        assert_eq!(m.into_inner(), NonCopy(20));
494    }
495
496    #[test]
497    fn test_rwlockguard_sync() {
498        fn sync<T: Sync>(_: T) {}
499
500        let rwlock = RwLock::new(());
501        sync(rwlock.read());
502        sync(rwlock.write());
503    }
504
505    #[test]
506    fn test_rwlock_downgrade() {
507        let x = Arc::new(RwLock::new(0));
508        let mut handles = Vec::new();
509        for _ in 0..8 {
510            let x = x.clone();
511            handles.push(thread::spawn(move || {
512                for _ in 0..100 {
513                    let mut writer = x.write();
514                    *writer += 1;
515                    let cur_val = *writer;
516                    let reader = RwLockWriteGuard::downgrade(writer);
517                    assert_eq!(cur_val, *reader);
518                }
519            }));
520        }
521        for handle in handles {
522            handle.join().unwrap()
523        }
524        assert_eq!(*x.read(), 800);
525    }
526
527    #[test]
528    fn test_rwlock_debug() {
529        let x = RwLock::new(vec![0u8, 10]);
530
531        assert_eq!(format!("{:?}", x), "RwLock { data: [0, 10] }");
532        let _lock = x.write();
533        assert_eq!(format!("{:?}", x), "RwLock { data: <locked> }");
534    }
535
536    #[test]
537    fn test_clone_through_guard() {
538        let rwlock = RwLock::new(Arc::new(1));
539        let a = rwlock.read();
540        // This must clone the protected Arc, not the read guard.
541        let b = a.clone();
542        assert_eq!(Arc::strong_count(&b), 2);
543    }
544
545    #[cfg(feature = "serde")]
546    #[test]
547    fn test_serde() {
548        let contents: Vec<u8> = vec![0, 1, 2];
549        let mutex = RwLock::new(contents.clone());
550
551        let serialized = to_stdvec(&mutex).unwrap();
552        let deserialized: RwLock<Vec<u8>> = from_bytes(&serialized).unwrap();
553
554        assert_eq!(*(mutex.read()), *(deserialized.read()));
555        assert_eq!(contents, *(deserialized.read()));
556    }
557
558    #[test]
559    fn test_issue_203() {
560        struct Bar(RwLock<()>);
561
562        impl Drop for Bar {
563            fn drop(&mut self) {
564                let _n = self.0.write();
565            }
566        }
567
568        thread_local! {
569            static B: Bar = const { Bar(RwLock::new(())) };
570        }
571
572        thread::spawn(|| {
573            B.with(|_| ());
574
575            let a = RwLock::new(());
576            let _a = a.read();
577        })
578        .join()
579        .unwrap();
580    }
581
582    #[test]
583    fn test_rw_write_is_locked() {
584        let lock = RwLock::new(0isize);
585        {
586            let _read_guard = lock.read();
587
588            assert!(lock.is_locked());
589            assert!(!lock.is_locked_exclusive());
590        }
591
592        {
593            let _write_guard = lock.write();
594
595            assert!(lock.is_locked());
596            assert!(lock.is_locked_exclusive());
597        }
598    }
599
600    #[test]
601    #[cfg(feature = "arc_lock")]
602    fn test_issue_430() {
603        let lock = std::sync::Arc::new(RwLock::new(0));
604
605        let mut rl = lock.upgradable_read_arc();
606
607        rl.with_upgraded(|_| {
608            println!("lock upgrade");
609        });
610
611        rl.with_upgraded(|_| {
612            println!("lock upgrade");
613        });
614
615        drop(lock);
616    }
617}