Skip to content

Commit 13d5c27

Browse files
authored
Rollup merge of rust-lang#73104 - poliorcetics:explicit-mutex-drop-example, r=dtolnay
Example about explicit mutex dropping Fixes rust-lang#67457. Following the remarks made in rust-lang#73074, I added an example on the main `Mutex` type, with a situation where there is mutable data and a computation result. In my testing it is effectively needed to explicitly drop the lock, else it deadlocks. r? @dtolnay because you were the one to review the previous PR.
2 parents 11b4ee9 + c010e71 commit 13d5c27

File tree

1 file changed

+54
-0
lines changed

1 file changed

+54
-0
lines changed

src/libstd/sync/mutex.rs

+54
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,60 @@ use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult};
107107
///
108108
/// *guard += 1;
109109
/// ```
110+
///
111+
/// It is sometimes necessary to manually drop the mutex guard to unlock it
112+
/// sooner than the end of the enclosing scope.
113+
///
114+
/// ```
115+
/// use std::sync::{Arc, Mutex};
116+
/// use std::thread;
117+
///
118+
/// const N: usize = 3;
119+
///
120+
/// let data_mutex = Arc::new(Mutex::new(vec![1, 2, 3, 4]));
121+
/// let res_mutex = Arc::new(Mutex::new(0));
122+
///
123+
/// let mut threads = Vec::with_capacity(N);
124+
/// (0..N).for_each(|_| {
125+
/// let data_mutex_clone = Arc::clone(&data_mutex);
126+
/// let res_mutex_clone = Arc::clone(&res_mutex);
127+
///
128+
/// threads.push(thread::spawn(move || {
129+
/// let mut data = data_mutex_clone.lock().unwrap();
130+
/// // This is the result of some important and long-ish work.
131+
/// let result = data.iter().fold(0, |acc, x| acc + x * 2);
132+
/// data.push(result);
133+
/// drop(data);
134+
/// *res_mutex_clone.lock().unwrap() += result;
135+
/// }));
136+
/// });
137+
///
138+
/// let mut data = data_mutex.lock().unwrap();
139+
/// // This is the result of some important and long-ish work.
140+
/// let result = data.iter().fold(0, |acc, x| acc + x * 2);
141+
/// data.push(result);
142+
/// // We drop the `data` explicitly because it's not necessary anymore and the
143+
/// // thread still has work to do. This allow other threads to start working on
144+
/// // the data immediately, without waiting for the rest of the unrelated work
145+
/// // to be done here.
146+
/// //
147+
/// // It's even more important here than in the threads because we `.join` the
148+
/// // threads after that. If we had not dropped the mutex guard, a thread could
149+
/// // be waiting forever for it, causing a deadlock.
150+
/// drop(data);
151+
/// // Here the mutex guard is not assigned to a variable and so, even if the
152+
/// // scope does not end after this line, the mutex is still released: there is
153+
/// // no deadlock.
154+
/// *res_mutex.lock().unwrap() += result;
155+
///
156+
/// threads.into_iter().for_each(|thread| {
157+
/// thread
158+
/// .join()
159+
/// .expect("The thread creating or execution failed !")
160+
/// });
161+
///
162+
/// assert_eq!(*res_mutex.lock().unwrap(), 800);
163+
/// ```
110164
#[stable(feature = "rust1", since = "1.0.0")]
111165
#[cfg_attr(not(test), rustc_diagnostic_item = "mutex_type")]
112166
pub struct Mutex<T: ?Sized> {

0 commit comments

Comments
 (0)