summaryrefslogtreecommitdiffstats
path: root/tokio/src/sync
diff options
context:
space:
mode:
authorMax Heller <max.a.heller@gmail.com>2020-09-11 16:00:04 -0400
committerGitHub <noreply@github.com>2020-09-11 22:00:04 +0200
commitc5a9ede157691ac5ca15283735bd666c6b016188 (patch)
treee0b73f8f0de40ce334ce7c40ff253ca72ce64d6f /tokio/src/sync
parentce0af8f7a188c9b8b8b4dcc3847674fd0afbe769 (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.rs52
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>