Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example about explicit mutex dropping #73104

Merged
merged 7 commits into from
Jun 15, 2020
55 changes: 55 additions & 0 deletions src/libstd/sync/mutex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,61 @@ use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult};
///
/// *guard += 1;
/// ```
///
/// It is sometimes a good idea (or even necessary) to manually drop the mutex
poliorcetics marked this conversation as resolved.
Show resolved Hide resolved
/// to unlock it as soon as possible. If you need the resource until the end of
poliorcetics marked this conversation as resolved.
Show resolved Hide resolved
/// the scope, this is not needed.
poliorcetics marked this conversation as resolved.
Show resolved Hide resolved
///
/// ```
/// use std::sync::{Arc, Mutex};
poliorcetics marked this conversation as resolved.
Show resolved Hide resolved
/// use std::thread;
///
/// const N: usize = 3;
///
/// let data_mutex = Arc::new(Mutex::new(vec![1, 2, 3, 4]));
/// let res_mutex = Arc::new(Mutex::new(0));
///
/// let mut threads = Vec::with_capacity(N);
/// (0..N).for_each(|_| {
/// let data_mutex_clone = Arc::clone(&data_mutex);
/// let res_mutex_clone = Arc::clone(&res_mutex);
///
/// threads.push(thread::spawn(move || {
/// let mut data = data_mutex_clone.lock().unwrap();
/// // This is the result of some important and long-ish work.
/// let result = data.iter().fold(0, |acc, x| acc + x * 2);
/// data.push(result);
/// drop(data);
/// *res_mutex_clone.lock().unwrap() += result;
/// }));
/// });
///
/// let mut data = data_mutex.lock().unwrap();
/// // This is the result of some important and long-ish work.
/// let result = data.iter().fold(0, |acc, x| acc + x * 2);
/// data.push(result);
/// // We drop the `data` explicitely because it's not necessary anymore
poliorcetics marked this conversation as resolved.
Show resolved Hide resolved
/// // and the thread still has work to do. This allow other threads to
/// // start working on the data immediately, without waiting
/// // for the rest of the unrelated work to be done here.
/// //
/// // It's even more important here than in the threads because we `.join` the
/// // threads after that. If we had not dropped the lock, a thread could be
poliorcetics marked this conversation as resolved.
Show resolved Hide resolved
/// // waiting forever for it, causing a deadlock.
/// drop(data);
/// // Here the lock is not assigned to a variable and so, even if the scope
poliorcetics marked this conversation as resolved.
Show resolved Hide resolved
/// // does not end after this line, the mutex is still released:
/// // there is no deadlock.
/// *res_mutex.lock().unwrap() += result;
poliorcetics marked this conversation as resolved.
Show resolved Hide resolved
///
/// threads.into_iter().for_each(|thread| {
/// thread
/// .join()
/// .expect("The thread creating or execution failed !")
/// });
///
/// assert_eq!(*res_mutex.lock().unwrap(), 800);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "mutex_type")]
pub struct Mutex<T: ?Sized> {
Expand Down