From b14f59736a90e7769b6f6ef23f634bdda866702f Mon Sep 17 00:00:00 2001 From: mark Date: Wed, 25 Nov 2020 20:12:30 -0600 Subject: [PATCH 1/2] add some convenience methods for locks. --- library/std/src/sync/mutex.rs | 75 ++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index a01ebb316e886..e13850c2b84b8 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -7,7 +7,7 @@ use crate::mem; use crate::ops::{Deref, DerefMut}; use crate::ptr; use crate::sys_common::mutex as sys; -use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult}; +use crate::sys_common::poison::{self, LockResult, PoisonError, TryLockError, TryLockResult}; /// A mutual exclusion primitive useful for protecting shared data /// @@ -399,6 +399,71 @@ impl Mutex { let data = self.data.get_mut(); poison::map_result(self.poison.borrow(), |_| data) } + + /// Run the given closure while holding the lock. The guarded value is mutably passed to the + /// closure, and the result of the closure is returned from `with`. + /// + /// This function is functionally equivalent to calling `lock` before the closure and dropping + /// the `MutexGuard` immediately after. + /// + /// # Errors + /// + /// If another user of this mutex panicked while holding the mutex, then + /// this call will return an error once the mutex is acquired. + /// + /// # Panics + /// + /// This function might panic when called if the lock is already held by + /// the current thread. + /// + /// # Example + /// + /// ``` + /// use std::sync::Mutex; + /// + /// let mutex = Mutex::new(0); + /// let result = mutex.with(|myint| { myint += 1; myint * 42 }).unwrap(); + /// assert_eq!(*mutex.lock().unwrap(), 1); + /// assert_eq!(result, 42); + /// ``` + #[unstable(feature = "mutex_with", issue = "none")] + pub fn with(&self, f: F) -> Result>> + where + F: FnOnce(&mut T) -> R, + { + Ok(f(&mut *self.lock()?)) + } + + /// Attempt to acquire the lock. If it cannot be acquired at this time, [`Err`] is returned. If + /// it is acquired, run the given closure with the lock held. + /// + /// This function is functionally equivalent to calling `try_lock`, and calling the closure if + /// the lock is acquired. After the closure is run, the `MutexGuard` is dropped immediately. + /// + /// This function does not block. + /// + /// # Errors + /// + /// If another user of this mutex panicked while holding the mutex, then + /// this call will return an error if the mutex would otherwise be + /// acquired. + /// + /// # Examples + /// ``` + /// use std::sync::Mutex; + /// + /// let mutex = Mutex::new(0); + /// let result = mutex.try_with(|myint| { myint += 1; myint * 42 }).unwrap(); + /// assert_eq!(*mutex.lock().unwrap(), 1); + /// assert_eq!(result, 42); + /// ``` + #[unstable(feature = "mutex_with", issue = "none")] + pub fn try_with(&self, f: F) -> Result>> + where + F: FnOnce(&mut T) -> R, + { + Ok(f(&mut *self.try_lock()?)) + } } #[stable(feature = "mutex_from", since = "1.24.0")] @@ -444,6 +509,14 @@ impl<'mutex, T: ?Sized> MutexGuard<'mutex, T> { unsafe fn new(lock: &'mutex Mutex) -> LockResult> { poison::map_result(lock.poison.borrow(), |guard| MutexGuard { lock, poison: guard }) } + + /// Immediately drops `self`, and consequently unlocks the mutex. + /// + /// This is equivalent to calling [`Drop::drop`] on the guard, but is more self-documenting. + #[unstable(feature = "guard_unlock", issue = "none")] + pub fn unlock(self) { + drop(self); + } } #[stable(feature = "rust1", since = "1.0.0")] From fd43ac39fadd9a2b3af4887b2e48c3113b70308f Mon Sep 17 00:00:00 2001 From: mark Date: Wed, 25 Nov 2020 23:35:08 -0600 Subject: [PATCH 2/2] fix doctests --- library/std/src/sync/mutex.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index e13850c2b84b8..7cccfd8686586 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -419,10 +419,11 @@ impl Mutex { /// # Example /// /// ``` + /// #![feature(mutex_with)] /// use std::sync::Mutex; /// /// let mutex = Mutex::new(0); - /// let result = mutex.with(|myint| { myint += 1; myint * 42 }).unwrap(); + /// let result = mutex.with(|myint| { *myint += 1; *myint * 42 }).unwrap(); /// assert_eq!(*mutex.lock().unwrap(), 1); /// assert_eq!(result, 42); /// ``` @@ -450,10 +451,11 @@ impl Mutex { /// /// # Examples /// ``` + /// #![feature(mutex_with)] /// use std::sync::Mutex; /// /// let mutex = Mutex::new(0); - /// let result = mutex.try_with(|myint| { myint += 1; myint * 42 }).unwrap(); + /// let result = mutex.try_with(|myint| { *myint += 1; *myint * 42 }).unwrap(); /// assert_eq!(*mutex.lock().unwrap(), 1); /// assert_eq!(result, 42); /// ```