diff options
author | Max Heller <max.a.heller@gmail.com> | 2020-09-11 16:00:04 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-11 22:00:04 +0200 |
commit | c5a9ede157691ac5ca15283735bd666c6b016188 (patch) | |
tree | e0b73f8f0de40ce334ce7c40ff253ca72ce64d6f /tokio/src/sync | |
parent | ce0af8f7a188c9b8b8b4dcc3847674fd0afbe769 (diff) |
sync: write guard to read guard downgrading for sync::RwLock (#2733)
Diffstat (limited to 'tokio/src/sync')
-rw-r--r-- | tokio/src/sync/rwlock.rs | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/tokio/src/sync/rwlock.rs b/tokio/src/sync/rwlock.rs index 373ab109..650a7cf6 100644 --- a/tokio/src/sync/rwlock.rs +++ b/tokio/src/sync/rwlock.rs @@ -344,6 +344,58 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { marker: marker::PhantomData, }) } + + /// Atomically downgrades a write lock into a read lock without allowing + /// any writers to take exclusive access of the lock in the meantime. + /// + /// **Note:** This won't *necessarily* allow any additional readers to acquire + /// locks, since [`RwLock`] is fair and it is possible that a writer is next + /// in line. + /// + /// Returns an RAII guard which will drop the read access of this rwlock + /// when dropped. + /// + /// # Examples + /// + /// ``` + /// # use tokio::sync::RwLock; + /// # use std::sync::Arc; + /// # + /// # #[tokio::main] + /// # async fn main() { + /// let lock = Arc::new(RwLock::new(1)); + /// + /// let n = lock.write().await; + /// + /// let cloned_lock = lock.clone(); + /// let handle = tokio::spawn(async move { + /// *cloned_lock.write().await = 2; + /// }); + /// + /// let n = n.downgrade(); + /// assert_eq!(*n, 1, "downgrade is atomic"); + /// + /// assert_eq!(*lock.read().await, 1, "additional readers can obtain locks"); + /// + /// drop(n); + /// handle.await.unwrap(); + /// assert_eq!(*lock.read().await, 2, "second writer obtained write lock"); + /// # } + /// ``` + /// + /// [`RwLock`]: struct@RwLock + pub fn downgrade(self) -> RwLockReadGuard<'a, T> { + let RwLockWriteGuard { s, data, .. } = self; + + // Release all but one of the permits held by the write guard + s.release(MAX_READS - 1); + + RwLockReadGuard { + s, + data, + marker: marker::PhantomData, + } + } } impl<'a, T: ?Sized> fmt::Debug for RwLockWriteGuard<'a, T> |