Skip to main content

parking_lot/
recursive_rwlock.rs

1use crate::RawRwLockRecursive;
2
3/// A reader-writer lock which permits recursive read locking.
4///
5/// This type of lock allows a number of readers or at most one writer at any
6/// point in time. Unlike [`RwLock`](crate::RwLock), a thread can hold multiple
7/// read locks without deadlocking, at the cost of allowing writers to starve.
8///
9/// # Examples
10///
11/// ```
12/// use parking_lot::RecursiveRwLock;
13///
14/// let lock = RecursiveRwLock::new(5);
15/// let first = lock.read();
16/// let second = lock.read();
17/// assert_eq!(*first, *second);
18/// ```
19pub type RecursiveRwLock<T> = lock_api::RwLock<RawRwLockRecursive, T>;
20
21/// An RAII guard which releases shared read access when dropped.
22pub type RecursiveRwLockReadGuard<'a, T> = lock_api::RwLockReadGuard<'a, RawRwLockRecursive, T>;
23
24/// An RAII guard which releases exclusive write access when dropped.
25pub type RecursiveRwLockWriteGuard<'a, T> = lock_api::RwLockWriteGuard<'a, RawRwLockRecursive, T>;
26
27/// An RAII guard which releases upgradable read access when dropped.
28pub type RecursiveRwLockUpgradableReadGuard<'a, T> =
29    lock_api::RwLockUpgradableReadGuard<'a, RawRwLockRecursive, T>;
30
31/// A mapped RAII guard which releases shared access when dropped.
32pub type MappedRecursiveRwLockReadGuard<'a, T> =
33    lock_api::MappedRwLockReadGuard<'a, RawRwLockRecursive, T>;
34
35/// A mapped RAII guard which releases exclusive access when dropped.
36pub type MappedRecursiveRwLockWriteGuard<'a, T> =
37    lock_api::MappedRwLockWriteGuard<'a, RawRwLockRecursive, T>;
38
39#[cfg(test)]
40mod tests {
41    use crate::{RecursiveRwLock, RecursiveRwLockReadGuard, RecursiveRwLockUpgradableReadGuard};
42    use rand::RngExt;
43    use std::sync::Arc;
44    use std::thread;
45
46    #[test]
47    fn frob() {
48        const N: u32 = 10;
49        const M: u32 = if cfg!(miri) { 100 } else { 1000 };
50
51        let lock = Arc::new(RecursiveRwLock::new(()));
52        let mut threads = Vec::new();
53        for _ in 0..N {
54            let lock = Arc::clone(&lock);
55            threads.push(thread::spawn(move || {
56                let mut rng = rand::rng();
57                for _ in 0..M {
58                    if rng.random_bool(1.0 / N as f64) {
59                        drop(lock.write());
60                    } else {
61                        drop(lock.read());
62                    }
63                }
64            }));
65        }
66        for thread in threads {
67            thread.join().unwrap();
68        }
69    }
70
71    #[test]
72    fn recursive_read_with_waiting_writer() {
73        let lock = Arc::new(RecursiveRwLock::new(()));
74        let first = lock.read();
75        let second = lock.read();
76
77        let lock2 = Arc::clone(&lock);
78        let writer = thread::spawn(move || drop(lock2.write()));
79        while !unsafe { lock.raw() }.has_parked_threads() {
80            thread::yield_now();
81        }
82
83        assert!(lock.try_read().is_some());
84        let mut second = second;
85        RecursiveRwLockReadGuard::bump(&mut second);
86
87        drop(first);
88        drop(second);
89        writer.join().unwrap();
90    }
91
92    #[test]
93    fn upgrade() {
94        let lock = RecursiveRwLock::new(1);
95        let upgradable = lock.upgradable_read();
96        let read = lock.read();
97        drop(read);
98        let mut write = RecursiveRwLockUpgradableReadGuard::upgrade(upgradable);
99        *write = 2;
100        drop(write);
101        assert_eq!(*lock.read(), 2);
102    }
103}