sync: write guard to read guard downgrading for sync::RwLock (#2733)

This commit is contained in:
Max Heller 2020-09-11 16:00:04 -04:00 committed by GitHub
parent ce0af8f7a1
commit c5a9ede157
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -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>