Skip to main content

parking_lot/
mutex.rs

1use crate::raw_mutex::RawMutex;
2
3/// A mutual exclusion primitive useful for protecting shared data.
4///
5/// This mutex will block threads waiting for the lock to become available. The
6/// mutex can be statically initialized or created by the `new`
7/// constructor. Each mutex has a type parameter which represents the data that
8/// it is protecting. The data can only be accessed through the RAII guards
9/// returned from `lock` and `try_lock`, which guarantees that the data is only
10/// ever accessed when the mutex is locked.
11///
12/// # Fairness
13///
14/// This mutex uses unfair unlocking by default, which allows the unlocking
15/// thread to re-acquire the mutex before a waiting thread and generally
16/// improves throughput. This can starve waiting threads.
17///
18/// Fair unlocking can be requested explicitly by calling
19/// `MutexGuard::unlock_fair` instead of simply dropping the `MutexGuard`. A
20/// fair unlock hands the mutex directly to a waiting thread.
21///
22/// # Differences from the standard library `Mutex`
23///
24/// - No poisoning, the lock is released normally on panic.
25/// - Only requires 1 byte of lock state.
26/// - Supports locking with a timeout.
27/// - Allows raw locking & unlocking without a guard.
28/// - Supports explicit fair unlocking through `MutexGuard::unlock_fair`.
29///
30/// # Examples
31///
32/// ```
33/// use parking_lot::Mutex;
34/// use std::sync::{Arc, mpsc::channel};
35/// use std::thread;
36///
37/// const N: usize = 10;
38///
39/// // Spawn a few threads to increment a shared variable (non-atomically), and
40/// // let the main thread know once all increments are done.
41/// //
42/// // Here we're using an Arc to share memory among threads, and the data inside
43/// // the Arc is protected with a mutex.
44/// let data = Arc::new(Mutex::new(0));
45///
46/// let (tx, rx) = channel();
47/// for _ in 0..N {
48///     let (data, tx) = (Arc::clone(&data), tx.clone());
49///     thread::spawn(move || {
50///         // The shared state can only be accessed once the lock is held.
51///         // Our non-atomic increment is safe because we're the only thread
52///         // which can access the shared state when the lock is held.
53///         let mut data = data.lock();
54///         *data += 1;
55///         if *data == N {
56///             tx.send(()).unwrap();
57///         }
58///         // the lock is unlocked here when `data` goes out of scope.
59///     });
60/// }
61///
62/// rx.recv().unwrap();
63/// ```
64pub type Mutex<T> = lock_api::Mutex<RawMutex, T>;
65
66/// An RAII guard which unlocks the mutex when dropped.
67///
68/// The data protected by the mutex can be accessed through this guard via its
69/// [`Deref`](core::ops::Deref) and [`DerefMut`](core::ops::DerefMut)
70/// implementations.
71pub type MutexGuard<'a, T> = lock_api::MutexGuard<'a, RawMutex, T>;
72
73/// An RAII mutex guard returned by [`MutexGuard::map`], which can point to a
74/// subfield of the protected data.
75///
76/// The main difference between `MappedMutexGuard` and `MutexGuard` is that the
77/// former doesn't support temporarily unlocking and re-locking, since that
78/// could introduce soundness issues if the locked object is modified by another
79/// thread.
80pub type MappedMutexGuard<'a, T> = lock_api::MappedMutexGuard<'a, RawMutex, T>;
81
82#[cfg(test)]
83mod tests {
84    use crate::{Condvar, MappedMutexGuard, Mutex, MutexGuard};
85    use std::collections::HashMap;
86    use std::ops::Deref;
87    use std::sync::Arc;
88    use std::sync::atomic::{AtomicUsize, Ordering};
89    use std::sync::mpsc::channel;
90    use std::thread;
91
92    #[cfg(feature = "serde")]
93    use postcard::{from_bytes, to_stdvec};
94
95    struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
96
97    #[derive(Eq, PartialEq, Debug)]
98    struct NonCopy(i32);
99
100    #[test]
101    fn smoke() {
102        let m = Mutex::new(());
103        drop(m.lock());
104        drop(m.lock());
105    }
106
107    #[test]
108    fn lots_and_lots() {
109        const J: u32 = if cfg!(miri) { 200 } else { 1000 };
110        const K: u32 = 3;
111
112        let m = Arc::new(Mutex::new(0));
113
114        fn inc(m: &Mutex<u32>) {
115            for _ in 0..J {
116                *m.lock() += 1;
117            }
118        }
119
120        let (tx, rx) = channel();
121        for _ in 0..K {
122            let tx2 = tx.clone();
123            let m2 = m.clone();
124            thread::spawn(move || {
125                inc(&m2);
126                tx2.send(()).unwrap();
127            });
128            let tx2 = tx.clone();
129            let m2 = m.clone();
130            thread::spawn(move || {
131                inc(&m2);
132                tx2.send(()).unwrap();
133            });
134        }
135
136        drop(tx);
137        for _ in 0..2 * K {
138            rx.recv().unwrap();
139        }
140        assert_eq!(*m.lock(), J * K * 2);
141    }
142
143    #[test]
144    fn try_lock() {
145        let m = Mutex::new(());
146        let guard = m.try_lock().unwrap();
147        assert!(m.try_lock().is_none());
148        drop(guard);
149        assert!(m.try_lock().is_some());
150    }
151
152    #[test]
153    fn test_into_inner() {
154        let m = Mutex::new(NonCopy(10));
155        assert_eq!(m.into_inner(), NonCopy(10));
156    }
157
158    #[test]
159    fn test_into_inner_drop() {
160        struct Foo(Arc<AtomicUsize>);
161        impl Drop for Foo {
162            fn drop(&mut self) {
163                self.0.fetch_add(1, Ordering::SeqCst);
164            }
165        }
166        let num_drops = Arc::new(AtomicUsize::new(0));
167        let m = Mutex::new(Foo(num_drops.clone()));
168        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
169        {
170            let _inner = m.into_inner();
171            assert_eq!(num_drops.load(Ordering::SeqCst), 0);
172        }
173        assert_eq!(num_drops.load(Ordering::SeqCst), 1);
174    }
175
176    #[test]
177    fn test_get_mut() {
178        let mut m = Mutex::new(NonCopy(10));
179        *m.get_mut() = NonCopy(20);
180        assert_eq!(m.into_inner(), NonCopy(20));
181    }
182
183    #[test]
184    fn test_mutex_arc_condvar() {
185        let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
186        let packet2 = Packet(packet.0.clone());
187        let (tx, rx) = channel();
188        let _t = thread::spawn(move || {
189            // wait until parent gets in
190            rx.recv().unwrap();
191            let (lock, cvar) = &*packet2.0;
192            let mut lock = lock.lock();
193            *lock = true;
194            cvar.notify_one();
195        });
196
197        let (lock, cvar) = &*packet.0;
198        let mut lock = lock.lock();
199        tx.send(()).unwrap();
200        assert!(!*lock);
201        while !*lock {
202            cvar.wait(&mut lock);
203        }
204    }
205
206    #[test]
207    fn test_mutex_arc_nested() {
208        // Tests nested mutexes and access
209        // to underlying data.
210        let arc = Arc::new(Mutex::new(1));
211        let arc2 = Arc::new(Mutex::new(arc));
212        let (tx, rx) = channel();
213        let _t = thread::spawn(move || {
214            let lock = arc2.lock();
215            let lock2 = lock.lock();
216            assert_eq!(*lock2, 1);
217            tx.send(()).unwrap();
218        });
219        rx.recv().unwrap();
220    }
221
222    #[test]
223    fn test_mutex_arc_access_in_unwind() {
224        let arc = Arc::new(Mutex::new(1));
225        let arc2 = arc.clone();
226        let _ = thread::spawn(move || {
227            struct Unwinder {
228                i: Arc<Mutex<i32>>,
229            }
230            impl Drop for Unwinder {
231                fn drop(&mut self) {
232                    *self.i.lock() += 1;
233                }
234            }
235            let _u = Unwinder { i: arc2 };
236            panic!();
237        })
238        .join();
239        let lock = arc.lock();
240        assert_eq!(*lock, 2);
241    }
242
243    #[test]
244    fn test_mutex_unsized() {
245        let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
246        {
247            let b = &mut *mutex.lock();
248            b[0] = 4;
249            b[2] = 5;
250        }
251        let comp: &[i32] = &[4, 2, 5];
252        assert_eq!(&*mutex.lock(), comp);
253    }
254
255    #[test]
256    fn test_mutexguard_sync() {
257        fn sync<T: Sync>(_: T) {}
258
259        let mutex = Mutex::new(());
260        sync(mutex.lock());
261    }
262
263    #[test]
264    fn test_mutex_debug() {
265        let mutex = Mutex::new(vec![0u8, 10]);
266
267        assert_eq!(format!("{:?}", mutex), "Mutex { data: [0, 10] }");
268        let _lock = mutex.lock();
269        assert_eq!(format!("{:?}", mutex), "Mutex { data: <locked> }");
270    }
271
272    #[cfg(feature = "serde")]
273    #[test]
274    fn test_serde() {
275        let contents: Vec<u8> = vec![0, 1, 2];
276        let mutex = Mutex::new(contents.clone());
277
278        let serialized = to_stdvec(&mutex).unwrap();
279        let deserialized: Mutex<Vec<u8>> = from_bytes(&serialized).unwrap();
280
281        assert_eq!(*(mutex.lock()), *(deserialized.lock()));
282        assert_eq!(contents, *(deserialized.lock()));
283    }
284
285    #[test]
286    fn test_map_or_err_not_mapped() {
287        let mut map = HashMap::new();
288        map.insert("hello".to_string(), "world".to_string());
289
290        let mutex = Mutex::new(map);
291        let guard = mutex.lock();
292        let guard = match MutexGuard::try_map_or_err(guard, |the_map| {
293            the_map.get_mut("hello2").ok_or(12345i32)
294        }) {
295            Ok(_) => unreachable!(),
296            Err((guard, data)) => {
297                assert_eq!(data, 12345i32);
298                assert_eq!(guard.get("hello"), Some(&"world".to_string()));
299                guard
300            }
301        };
302
303        // Lets try again
304        let mapped_guard = match MutexGuard::try_map_or_err(guard, |the_map| {
305            the_map.get_mut("hello").ok_or("unreachable")
306        }) {
307            Ok(mapped_guard) => mapped_guard,
308            Err((_, _)) => unreachable!(),
309        };
310
311        assert_eq!(mapped_guard.as_str(), "world");
312
313        match MappedMutexGuard::try_map_or_err(mapped_guard, |the_string| {
314            if the_string != "world" {
315                //unreachable
316                Ok(the_string.as_mut_str())
317            } else {
318                Err(45678i32)
319            }
320        }) {
321            Ok(_) => unreachable!(),
322            Err((guard, err)) => {
323                assert_eq!(guard.as_str(), "world");
324                assert_eq!(err, 45678i32);
325            }
326        };
327    }
328
329    #[test]
330    fn test_map_or_err_mapped() {
331        let mut map = HashMap::new();
332        map.insert("hello".to_string(), "world".to_string());
333
334        let mutex = Mutex::new(map);
335        let guard = mutex.lock();
336        let mapped_guard = match MutexGuard::try_map_or_err(guard, |the_map| {
337            the_map.get_mut("hello").ok_or("unreachable")
338        }) {
339            Ok(mapped_guard) => mapped_guard,
340            Err((_, _)) => unreachable!(),
341        };
342
343        assert_eq!(mapped_guard.as_str(), "world");
344
345        match MappedMutexGuard::try_map_or_err(mapped_guard, |the_string| {
346            if the_string == "world" {
347                Ok(the_string.as_mut_str())
348            } else {
349                Err("unreachable")
350            }
351        }) {
352            Ok(mapped_guard) => assert_eq!(mapped_guard.deref(), "world"),
353            Err((_, _)) => unreachable!(),
354        };
355    }
356}