Skip to content

Commit 95c4899

Browse files
committed
Added an example where explicitly dropping a lock is necessary/a good idea.
1 parent f9fdf64 commit 95c4899

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed

src/libstd/sync/mutex.rs

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

0 commit comments

Comments
 (0)