parking_lot/
mutex.rs

1// Copyright 2016 Amanieu d'Antras
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use crate::raw_mutex::RawMutex;
9
10/// A mutual exclusion primitive useful for protecting shared data
11///
12/// This mutex will block threads waiting for the lock to become available. The
13/// mutex can be statically initialized or created by the `new`
14/// constructor. Each mutex has a type parameter which represents the data that
15/// it is protecting. The data can only be accessed through the RAII guards
16/// returned from `lock` and `try_lock`, which guarantees that the data is only
17/// ever accessed when the mutex is locked.
18///
19/// # Fairness
20///
21/// A typical unfair lock can often end up in a situation where a single thread
22/// quickly acquires and releases the same mutex in succession, which can starve
23/// other threads waiting to acquire the mutex. While this improves throughput
24/// because it doesn't force a context switch when a thread tries to re-acquire
25/// a mutex it has just released, this can starve other threads.
26///
27/// This mutex uses [eventual fairness](https://trac.webkit.org/changeset/203350)
28/// to ensure that the lock will be fair on average without sacrificing
29/// throughput. This is done by forcing a fair unlock on average every 0.5ms,
30/// which will force the lock to go to the next thread waiting for the mutex.
31///
32/// Additionally, any critical section longer than 1ms will always use a fair
33/// unlock, which has a negligible impact on throughput considering the length
34/// of the critical section.
35///
36/// You can also force a fair unlock by calling `MutexGuard::unlock_fair` when
37/// unlocking a mutex instead of simply dropping the `MutexGuard`.
38///
39/// # Differences from the standard library `Mutex`
40///
41/// - No poisoning, the lock is released normally on panic.
42/// - Only requires 1 byte of space, whereas the standard library boxes the
43///   `Mutex` due to platform limitations.
44/// - Can be statically constructed.
45/// - Does not require any drop glue when dropped.
46/// - Inline fast path for the uncontended case.
47/// - Efficient handling of micro-contention using adaptive spinning.
48/// - Allows raw locking & unlocking without a guard.
49/// - Supports eventual fairness so that the mutex is fair on average.
50/// - Optionally allows making the mutex fair by calling `MutexGuard::unlock_fair`.
51///
52/// # Examples
53///
54/// ```
55/// use parking_lot::Mutex;
56/// use std::sync::{Arc, mpsc::channel};
57/// use std::thread;
58///
59/// const N: usize = 10;
60///
61/// // Spawn a few threads to increment a shared variable (non-atomically), and
62/// // let the main thread know once all increments are done.
63/// //
64/// // Here we're using an Arc to share memory among threads, and the data inside
65/// // the Arc is protected with a mutex.
66/// let data = Arc::new(Mutex::new(0));
67///
68/// let (tx, rx) = channel();
69/// for _ in 0..10 {
70///     let (data, tx) = (Arc::clone(&data), tx.clone());
71///     thread::spawn(move || {
72///         // The shared state can only be accessed once the lock is held.
73///         // Our non-atomic increment is safe because we're the only thread
74///         // which can access the shared state when the lock is held.
75///         let mut data = data.lock();
76///         *data += 1;
77///         if *data == N {
78///             tx.send(()).unwrap();
79///         }
80///         // the lock is unlocked here when `data` goes out of scope.
81///     });
82/// }
83///
84/// rx.recv().unwrap();
85/// ```
86pub type Mutex<T> = lock_api::Mutex<RawMutex, T>;
87
88/// Creates a new mutex in an unlocked state ready for use.
89///
90/// This allows creating a mutex in a constant context on stable Rust.
91pub const fn const_mutex<T>(val: T) -> Mutex<T> {
92    Mutex::const_new(<RawMutex as lock_api::RawMutex>::INIT, val)
93}
94
95/// An RAII implementation of a "scoped lock" of a mutex. When this structure is
96/// dropped (falls out of scope), the lock will be unlocked.
97///
98/// The data protected by the mutex can be accessed through this guard via its
99/// `Deref` and `DerefMut` implementations.
100pub type MutexGuard<'a, T> = lock_api::MutexGuard<'a, RawMutex, T>;
101
102/// An RAII mutex guard returned by `MutexGuard::map`, which can point to a
103/// subfield of the protected data.
104///
105/// The main difference between `MappedMutexGuard` and `MutexGuard` is that the
106/// former doesn't support temporarily unlocking and re-locking, since that
107/// could introduce soundness issues if the locked object is modified by another
108/// thread.
109pub type MappedMutexGuard<'a, T> = lock_api::MappedMutexGuard<'a, RawMutex, T>;
110
111#[cfg(test)]
112mod tests {
113    use crate::{Condvar, MappedMutexGuard, Mutex, MutexGuard};
114    use std::collections::HashMap;
115    use std::ops::Deref;
116    use std::sync::atomic::{AtomicUsize, Ordering};
117    use std::sync::mpsc::channel;
118    use std::sync::Arc;
119    use std::thread;
120
121    #[cfg(feature = "serde")]
122    use bincode::{deserialize, serialize};
123
124    struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
125
126    #[derive(Eq, PartialEq, Debug)]
127    struct NonCopy(i32);
128
129    unsafe impl<T: Send> Send for Packet<T> {}
130    unsafe impl<T> Sync for Packet<T> {}
131
132    #[test]
133    fn smoke() {
134        let m = Mutex::new(());
135        drop(m.lock());
136        drop(m.lock());
137    }
138
139    #[test]
140    fn lots_and_lots() {
141        const J: u32 = 1000;
142        const K: u32 = 3;
143
144        let m = Arc::new(Mutex::new(0));
145
146        fn inc(m: &Mutex<u32>) {
147            for _ in 0..J {
148                *m.lock() += 1;
149            }
150        }
151
152        let (tx, rx) = channel();
153        for _ in 0..K {
154            let tx2 = tx.clone();
155            let m2 = m.clone();
156            thread::spawn(move || {
157                inc(&m2);
158                tx2.send(()).unwrap();
159            });
160            let tx2 = tx.clone();
161            let m2 = m.clone();
162            thread::spawn(move || {
163                inc(&m2);
164                tx2.send(()).unwrap();
165            });
166        }
167
168        drop(tx);
169        for _ in 0..2 * K {
170            rx.recv().unwrap();
171        }
172        assert_eq!(*m.lock(), J * K * 2);
173    }
174
175    #[test]
176    fn try_lock() {
177        let m = Mutex::new(());
178        *m.try_lock().unwrap() = ();
179    }
180
181    #[test]
182    fn test_into_inner() {
183        let m = Mutex::new(NonCopy(10));
184        assert_eq!(m.into_inner(), NonCopy(10));
185    }
186
187    #[test]
188    fn test_into_inner_drop() {
189        struct Foo(Arc<AtomicUsize>);
190        impl Drop for Foo {
191            fn drop(&mut self) {
192                self.0.fetch_add(1, Ordering::SeqCst);
193            }
194        }
195        let num_drops = Arc::new(AtomicUsize::new(0));
196        let m = Mutex::new(Foo(num_drops.clone()));
197        assert_eq!(num_drops.load(Ordering::SeqCst), 0);
198        {
199            let _inner = m.into_inner();
200            assert_eq!(num_drops.load(Ordering::SeqCst), 0);
201        }
202        assert_eq!(num_drops.load(Ordering::SeqCst), 1);
203    }
204
205    #[test]
206    fn test_get_mut() {
207        let mut m = Mutex::new(NonCopy(10));
208        *m.get_mut() = NonCopy(20);
209        assert_eq!(m.into_inner(), NonCopy(20));
210    }
211
212    #[test]
213    fn test_mutex_arc_condvar() {
214        let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
215        let packet2 = Packet(packet.0.clone());
216        let (tx, rx) = channel();
217        let _t = thread::spawn(move || {
218            // wait until parent gets in
219            rx.recv().unwrap();
220            let (lock, cvar) = &*packet2.0;
221            let mut lock = lock.lock();
222            *lock = true;
223            cvar.notify_one();
224        });
225
226        let (lock, cvar) = &*packet.0;
227        let mut lock = lock.lock();
228        tx.send(()).unwrap();
229        assert!(!*lock);
230        while !*lock {
231            cvar.wait(&mut lock);
232        }
233    }
234
235    #[test]
236    fn test_mutex_arc_nested() {
237        // Tests nested mutexes and access
238        // to underlying data.
239        let arc = Arc::new(Mutex::new(1));
240        let arc2 = Arc::new(Mutex::new(arc));
241        let (tx, rx) = channel();
242        let _t = thread::spawn(move || {
243            let lock = arc2.lock();
244            let lock2 = lock.lock();
245            assert_eq!(*lock2, 1);
246            tx.send(()).unwrap();
247        });
248        rx.recv().unwrap();
249    }
250
251    #[test]
252    fn test_mutex_arc_access_in_unwind() {
253        let arc = Arc::new(Mutex::new(1));
254        let arc2 = arc.clone();
255        let _ = thread::spawn(move || {
256            struct Unwinder {
257                i: Arc<Mutex<i32>>,
258            }
259            impl Drop for Unwinder {
260                fn drop(&mut self) {
261                    *self.i.lock() += 1;
262                }
263            }
264            let _u = Unwinder { i: arc2 };
265            panic!();
266        })
267        .join();
268        let lock = arc.lock();
269        assert_eq!(*lock, 2);
270    }
271
272    #[test]
273    fn test_mutex_unsized() {
274        let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
275        {
276            let b = &mut *mutex.lock();
277            b[0] = 4;
278            b[2] = 5;
279        }
280        let comp: &[i32] = &[4, 2, 5];
281        assert_eq!(&*mutex.lock(), comp);
282    }
283
284    #[test]
285    fn test_mutexguard_sync() {
286        fn sync<T: Sync>(_: T) {}
287
288        let mutex = Mutex::new(());
289        sync(mutex.lock());
290    }
291
292    #[test]
293    fn test_mutex_debug() {
294        let mutex = Mutex::new(vec![0u8, 10]);
295
296        assert_eq!(format!("{:?}", mutex), "Mutex { data: [0, 10] }");
297        let _lock = mutex.lock();
298        assert_eq!(format!("{:?}", mutex), "Mutex { data: <locked> }");
299    }
300
301    #[cfg(feature = "serde")]
302    #[test]
303    fn test_serde() {
304        let contents: Vec<u8> = vec![0, 1, 2];
305        let mutex = Mutex::new(contents.clone());
306
307        let serialized = serialize(&mutex).unwrap();
308        let deserialized: Mutex<Vec<u8>> = deserialize(&serialized).unwrap();
309
310        assert_eq!(*(mutex.lock()), *(deserialized.lock()));
311        assert_eq!(contents, *(deserialized.lock()));
312    }
313
314    #[test]
315    fn test_map_or_err_not_mapped() {
316        let mut map = HashMap::new();
317        map.insert("hello".to_string(), "world".to_string());
318
319        let mutex = Mutex::new(map);
320        let guard = mutex.lock();
321        let guard = match MutexGuard::try_map_or_err(guard, |the_map| {
322            the_map.get_mut("hello2").ok_or(12345i32)
323        }) {
324            Ok(_) => unreachable!(),
325            Err((guard, data)) => {
326                assert_eq!(data, 12345i32);
327                assert_eq!(guard.get("hello"), Some(&"world".to_string()));
328                guard
329            }
330        };
331
332        // Lets try again
333        let mapped_guard = match MutexGuard::try_map_or_err(guard, |the_map| {
334            the_map.get_mut("hello").ok_or("unreachable")
335        }) {
336            Ok(mapped_guard) => mapped_guard,
337            Err((_, _)) => unreachable!(),
338        };
339
340        assert_eq!(mapped_guard.as_str(), "world");
341
342        match MappedMutexGuard::try_map_or_err(mapped_guard, |the_string| {
343            if the_string != "world" {
344                //unreachable
345                Ok(the_string.as_mut_str())
346            } else {
347                Err(45678i32)
348            }
349        }) {
350            Ok(_) => unreachable!(),
351            Err((guard, err)) => {
352                assert_eq!(guard.as_str(), "world");
353                assert_eq!(err, 45678i32);
354            }
355        };
356    }
357
358    #[test]
359    fn test_map_or_err_mapped() {
360        let mut map = HashMap::new();
361        map.insert("hello".to_string(), "world".to_string());
362
363        let mutex = Mutex::new(map);
364        let guard = mutex.lock();
365        let mapped_guard = match MutexGuard::try_map_or_err(guard, |the_map| {
366            the_map.get_mut("hello").ok_or("unreachable")
367        }) {
368            Ok(mapped_guard) => mapped_guard,
369            Err((_, _)) => unreachable!(),
370        };
371
372        assert_eq!(mapped_guard.as_str(), "world");
373
374        match MappedMutexGuard::try_map_or_err(mapped_guard, |the_string| {
375            if the_string == "world" {
376                Ok(the_string.as_mut_str())
377            } else {
378                Err("unreachable")
379            }
380        }) {
381            Ok(mapped_guard) => assert_eq!(mapped_guard.deref(), "world"),
382            Err((_, _)) => unreachable!(),
383        };
384    }
385}