pub struct RwLock<T: ?Sized> { /* 私有字段 */ }展开描述
异步读写锁。
这种类型的锁允许任意数量的读者或在任意时刻最多一个写者。此锁的写部分通常允许修改底层数据(独占访问),而读部分通常允许只读访问(共享访问)。
相比之下,Mutex 不区分获取锁的读者或写者,因此会导致任何等待锁变得可用的任务让步。只要没有写者持有锁,RwLock 就允许任意数量的读者获取该锁。
Tokio 读写锁的优先级策略是公平的(或优先写者),以确保读者不会饿死写者。公平性通过对等待锁的任务使用先进先出队列来保证;在其之前排队的所有写锁请求被获取并释放之前,不会发出读锁。这与 Rust 标准库的 std::sync::RwLock 形成对比,后者的优先级策略取决于操作系统的实现。
类型参数 T 表示此锁保护的数据。要求 T 满足 Send 才能跨线程共享。加锁方法返回的 RAII guard 实现了 Deref(以及 write 方法的 DerefMut),以允许访问锁的内容。
§示例
use tokio::sync::RwLock;
let lock = RwLock::new(5);
// many reader locks can be held at once
{
let r1 = lock.read().await;
let r2 = lock.read().await;
assert_eq!(*r1, 5);
assert_eq!(*r2, 5);
} // read locks are dropped at this point
// only one write lock may be held, however
{
let mut w = lock.write().await;
*w += 1;
assert_eq!(*w, 6);
} // write lock is dropped here实现§
源代码§impl<T: ?Sized> RwLock<T>
impl<T: ?Sized> RwLock<T>
源代码pub fn with_max_readers(value: T, max_reads: u32) -> RwLock<T>where
T: Sized,
pub fn with_max_readers(value: T, max_reads: u32) -> RwLock<T>where
T: Sized,
源代码pub const fn const_new(value: T) -> RwLock<T>where
T: Sized,
pub const fn const_new(value: T) -> RwLock<T>where
T: Sized,
创建一个未锁定的 RwLock<T> 新实例。
当使用 tracing 不稳定功能 时,使用 const_new 创建的 RwLock 不会被检测。因此,它在 tokio-console 中不可见。如果需要,应改用 RwLock::new 创建被检测的对象。
§示例
use tokio::sync::RwLock;
static LOCK: RwLock<i32> = RwLock::const_new(5);源代码pub const fn const_with_max_readers(value: T, max_reads: u32) -> RwLock<T>where
T: Sized,
pub const fn const_with_max_readers(value: T, max_reads: u32) -> RwLock<T>where
T: Sized,
源代码pub async fn read(&self) -> RwLockReadGuard<'_, T>
pub async fn read(&self) -> RwLockReadGuard<'_, T>
使用共享读访问锁定此 RwLock,导致当前任务让出执行权,直到锁被获取。
调用任务将让出执行权,直到没有任何持有锁的写入者。当任务恢复时,锁内可能还有其他读取者。
请注意,根据 RwLock 的优先级策略,为防止饥饿,在先前的写锁释放之前不会授予读锁。因此,如果当前任务持有读锁,然后尝试获取写锁,再尝试获取读锁,则可能发生死锁。
返回一个 RAII 守卫,当它被 drop 时会释放此 RwLock 的读访问权。
§取消安全性
此方法使用队列按请求的顺序公平地分配锁。取消对 read 的调用会使你失去在队列中的位置。
§示例
use std::sync::Arc;
use tokio::sync::RwLock;
let lock = Arc::new(RwLock::new(1));
let c_lock = lock.clone();
let n = lock.read().await;
assert_eq!(*n, 1);
tokio::spawn(async move {
// While main has an active read lock, we acquire one too.
let r = c_lock.read().await;
assert_eq!(*r, 1);
}).await.expect("The spawned task has panicked");
// Drop the guard after the spawned task finishes.
drop(n);源代码pub fn blocking_read(&self) -> RwLockReadGuard<'_, T>
pub fn blocking_read(&self) -> RwLockReadGuard<'_, T>
以共享读访问阻塞方式锁定此 RwLock。
此方法适用于需要在异步代码和同步代码中都使用此 rwlock 的场景。
返回一个 RAII guard,当 drop 时将释放此 RwLock 的读访问权限。
§恐慌
如果在异步执行上下文中调用,此函数会发生 panic。
- If you find yourself in an asynchronous execution context and needing
to call some (synchronous) function which performs one of these
blocking_operations, then consider wrapping that call insidespawn_blocking()(or [block_in_place()][crate::task::block_in_place]).
§示例
use std::sync::Arc;
use tokio::sync::RwLock;
#[tokio::main]
async fn main() {
let rwlock = Arc::new(RwLock::new(1));
let mut write_lock = rwlock.write().await;
let blocking_task = tokio::task::spawn_blocking({
let rwlock = Arc::clone(&rwlock);
move || {
// This shall block until the `write_lock` is released.
let read_lock = rwlock.blocking_read();
assert_eq!(*read_lock, 0);
}
});
*write_lock -= 1;
drop(write_lock); // release the lock.
// Await the completion of the blocking task.
blocking_task.await.unwrap();
// Assert uncontended.
assert!(rwlock.try_write().is_ok());
}源代码pub async fn read_owned(self: Arc<Self>) -> OwnedRwLockReadGuard<T>
pub async fn read_owned(self: Arc<Self>) -> OwnedRwLockReadGuard<T>
使用共享读访问锁定此 RwLock,导致当前任务让出执行权,直到锁被获取。
调用任务将让出执行权,直到没有任何持有锁的写入者。当任务恢复时,锁内可能还有其他读取者。
此方法与 RwLock::read 相同,只是返回的 guard 通过 Arc 引用 RwLock 而不是借用它。因此,要调用此方法,RwLock 必须包装在 Arc 中,并且 guard 的生命周期为 'static,因为它通过持有 Arc 来保持 RwLock 存活。
请注意,根据 RwLock 的优先级策略,为防止饥饿,在先前的写锁释放之前不会授予读锁。因此,如果当前任务持有读锁,然后尝试获取写锁,再尝试获取读锁,则可能发生死锁。
返回一个 RAII 守卫,当它被 drop 时会释放此 RwLock 的读访问权。
§取消安全性
此方法使用队列按请求的顺序公平地分配锁。取消对 read_owned 的调用会使你失去在队列中的位置。
§示例
use std::sync::Arc;
use tokio::sync::RwLock;
let lock = Arc::new(RwLock::new(1));
let c_lock = lock.clone();
let n = lock.read_owned().await;
assert_eq!(*n, 1);
tokio::spawn(async move {
// While main has an active read lock, we acquire one too.
let r = c_lock.read_owned().await;
assert_eq!(*r, 1);
}).await.expect("The spawned task has panicked");
// Drop the guard after the spawned task finishes.
drop(n);
}源代码pub fn try_read(&self) -> Result<RwLockReadGuard<'_, T>, TryLockError>
pub fn try_read(&self) -> Result<RwLockReadGuard<'_, T>, TryLockError>
尝试使用共享读访问获取此 RwLock。
如果无法立即获取访问权限,则返回 TryLockError。否则返回一个 RAII 守卫,当它被 drop 时会释放读访问权。
§示例
use std::sync::Arc;
use tokio::sync::RwLock;
let lock = Arc::new(RwLock::new(1));
let c_lock = lock.clone();
let v = lock.try_read().unwrap();
assert_eq!(*v, 1);
tokio::spawn(async move {
// While main has an active read lock, we acquire one too.
let n = c_lock.read().await;
assert_eq!(*n, 1);
}).await.expect("The spawned task has panicked");
// Drop the guard when spawned task finishes.
drop(v);源代码pub fn try_read_owned(
self: Arc<Self>,
) -> Result<OwnedRwLockReadGuard<T>, TryLockError>
pub fn try_read_owned( self: Arc<Self>, ) -> Result<OwnedRwLockReadGuard<T>, TryLockError>
尝试使用共享读访问获取此 RwLock。
如果无法立即获取访问权限,则返回 TryLockError。否则返回一个 RAII 守卫,当它被 drop 时会释放读访问权。
此方法与 RwLock::try_read 相同,只是返回的 guard 通过 Arc 引用 RwLock 而不是借用它。因此,要调用此方法,RwLock 必须包装在 Arc 中,并且 guard 的生命周期为 'static,因为它通过持有 Arc 来保持 RwLock 存活。
§示例
use std::sync::Arc;
use tokio::sync::RwLock;
let lock = Arc::new(RwLock::new(1));
let c_lock = lock.clone();
let v = lock.try_read_owned().unwrap();
assert_eq!(*v, 1);
tokio::spawn(async move {
// While main has an active read lock, we acquire one too.
let n = c_lock.read_owned().await;
assert_eq!(*n, 1);
}).await.expect("The spawned task has panicked");
// Drop the guard when spawned task finishes.
drop(v);源代码pub async fn write(&self) -> RwLockWriteGuard<'_, T>
pub async fn write(&self) -> RwLockWriteGuard<'_, T>
源代码pub fn blocking_write(&self) -> RwLockWriteGuard<'_, T>
pub fn blocking_write(&self) -> RwLockWriteGuard<'_, T>
以独占写访问阻塞方式锁定此 RwLock。
此方法适用于需要在异步代码和同步代码中都使用此 rwlock 的场景。
返回一个 RAII 守卫,当它被 drop 时会释放此 RwLock 的写访问权。
§恐慌
如果在异步执行上下文中调用,此函数会发生 panic。
- If you find yourself in an asynchronous execution context and needing
to call some (synchronous) function which performs one of these
blocking_operations, then consider wrapping that call insidespawn_blocking()(or [block_in_place()][crate::task::block_in_place]).
§示例
use std::sync::Arc;
use tokio::{sync::RwLock};
#[tokio::main]
async fn main() {
let rwlock = Arc::new(RwLock::new(1));
let read_lock = rwlock.read().await;
let blocking_task = tokio::task::spawn_blocking({
let rwlock = Arc::clone(&rwlock);
move || {
// This shall block until the `read_lock` is released.
let mut write_lock = rwlock.blocking_write();
*write_lock = 2;
}
});
assert_eq!(*read_lock, 1);
// Release the last outstanding read lock.
drop(read_lock);
// Await the completion of the blocking task.
blocking_task.await.unwrap();
// Assert uncontended.
let read_lock = rwlock.try_read().unwrap();
assert_eq!(*read_lock, 2);
}源代码pub async fn write_owned(self: Arc<Self>) -> OwnedRwLockWriteGuard<T>
pub async fn write_owned(self: Arc<Self>) -> OwnedRwLockWriteGuard<T>
使用独占写访问锁定此 RwLock,导致当前任务让出执行权,直到锁被获取。
当其他写入者或读取者持有锁时,调用任务将让出执行权。
此方法与 RwLock::write 相同,只是返回的 guard 通过 Arc 引用 RwLock 而不是借用它。因此,要调用此方法,RwLock 必须包装在 Arc 中,并且 guard 的生命周期为 'static,因为它通过持有 Arc 来保持 RwLock 存活。
返回一个 RAII 守卫,当它被 drop 时会释放此 RwLock 的写访问权。
§取消安全性
此方法使用队列按请求的顺序公平地分配锁。取消对 write_owned 的调用会使你失去在队列中的位置。
§示例
use std::sync::Arc;
use tokio::sync::RwLock;
let lock = Arc::new(RwLock::new(1));
let mut n = lock.write_owned().await;
*n = 2;
}源代码pub fn try_write(&self) -> Result<RwLockWriteGuard<'_, T>, TryLockError>
pub fn try_write(&self) -> Result<RwLockWriteGuard<'_, T>, TryLockError>
尝试使用独占写访问获取此 RwLock。
如果无法立即获取访问权限,则返回 TryLockError。否则返回一个 RAII 守卫,当它被 drop 时会释放写访问权。
§示例
use tokio::sync::RwLock;
let rw = RwLock::new(1);
let v = rw.read().await;
assert_eq!(*v, 1);
assert!(rw.try_write().is_err());源代码pub fn try_write_owned(
self: Arc<Self>,
) -> Result<OwnedRwLockWriteGuard<T>, TryLockError>
pub fn try_write_owned( self: Arc<Self>, ) -> Result<OwnedRwLockWriteGuard<T>, TryLockError>
尝试使用独占写访问获取此 RwLock。
如果无法立即获取访问权限,则返回 TryLockError。否则返回一个 RAII 守卫,当它被 drop 时会释放写访问权。
此方法与 RwLock::try_write 相同,只是返回的 guard 通过 Arc 引用 RwLock 而不是借用它。因此,要调用此方法,RwLock 必须包装在 Arc 中,并且 guard 的生命周期为 'static,因为它通过持有 Arc 来保持 RwLock 存活。
§示例
use std::sync::Arc;
use tokio::sync::RwLock;
let rw = Arc::new(RwLock::new(1));
let v = Arc::clone(&rw).read_owned().await;
assert_eq!(*v, 1);
assert!(rw.try_write_owned().is_err());源代码pub fn get_mut(&mut self) -> &mut T
pub fn get_mut(&mut self) -> &mut T
返回对底层数据的可变引用。
由于此调用可变地借用 RwLock,因此无需实际进行锁定——可变借用在静态上保证不存在锁。
§示例
use tokio::sync::RwLock;
fn main() {
let mut lock = RwLock::new(1);
let n = lock.get_mut();
*n = 2;
}源代码pub fn into_inner(self) -> Twhere
T: Sized,
pub fn into_inner(self) -> Twhere
T: Sized,
消费该锁,返回底层数据。