跳到主要内容

RwLock

搜索

结构体 RwLock 

源代码
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>

源代码

pub fn new(value: T) -> RwLock<T>
where T: Sized,

创建一个未锁定的 RwLock<T> 新实例。

§示例
use tokio::sync::RwLock;

let lock = RwLock::new(5);
源代码

pub fn with_max_readers(value: T, max_reads: u32) -> RwLock<T>
where T: Sized,

创建一个未锁定的 RwLock<T> 新实例,允许最多 max_reads 个并发读取者。

§示例
use tokio::sync::RwLock;

let lock = RwLock::with_max_readers(5, 1024);
§恐慌

如果 max_reads0 或大于 u32::MAX >> 3,则会发生 panic。

源代码

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,

创建一个未锁定的 RwLock<T> 新实例,允许最多 max_reads 个并发读取者。

§示例
use tokio::sync::RwLock;

static LOCK: RwLock<i32> = RwLock::const_with_max_readers(5, 1024);
§恐慌

如果 max_reads0 或大于 u32::MAX >> 3,则会发生 panic。

源代码

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>

以共享读访问阻塞方式锁定此 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 inside spawn_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>

使用共享读访问锁定此 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>

尝试使用共享读访问获取此 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>

尝试使用共享读访问获取此 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>

使用独占写访问锁定此 RwLock,导致当前任务让出执行权,直到锁被获取。

当其他写入者或读取者持有锁时,调用任务将让出执行权。

返回一个 RAII 守卫,当它被 drop 时会释放此 RwLock 的写访问权。

§取消安全性

此方法使用队列按请求的顺序公平地分配锁。取消对 write 的调用会使你失去在队列中的位置。

§示例
use tokio::sync::RwLock;

let lock = RwLock::new(1);

let mut n = lock.write().await;
*n = 2;
源代码

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 inside spawn_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>

使用独占写访问锁定此 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>

尝试使用独占写访问获取此 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>

尝试使用独占写访问获取此 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

返回对底层数据的可变引用。

由于此调用可变地借用 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) -> T
where T: Sized,

消费该锁,返回底层数据。

trait 实现§

源代码§

impl<T> Debug for RwLock<T>
where T: Debug + ?Sized,

源代码§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

使用给定的格式化器格式化此值。 更多信息
源代码§

impl<T> 默认值 for RwLock<T>
where T: 默认值,

源代码§

fn default() -> Self

Returns the “default value” for a type. 更多信息
源代码§

impl<T> From<T> for RwLock<T>

源代码§

fn from(s: T) -> Self

从输入类型转换为此类型。
源代码§

impl<T> Send for RwLock<T>
where T: ?Sized + Send,

源代码§

impl<T> Sync for RwLock<T>
where T: ?Sized + Send + Sync,

自动 trait 实现§

§

impl<T> !Freeze for RwLock<T>

§

impl<T> !RefUnwindSafe for RwLock<T>

§

impl<T> Unpin for RwLock<T>
where T: Unpin + ?Sized,

§

impl<T> UnsafeUnpin for RwLock<T>
where T: UnsafeUnpin + ?Sized,

§

impl<T> UnwindSafe for RwLock<T>
where T: UnwindSafe + ?Sized,

blanket 实现§

源代码§

impl<T> Any for T
where T: 'static + ?Sized,

源代码§

fn type_id(&self) -> TypeId

Gets the TypeId of self. 更多信息
源代码§

impl<T> Borrow<T> for T
where T: ?Sized,

源代码§

fn borrow(&self) -> &T

Immutably borrows from an owned value. 更多信息
源代码§

impl<T> BorrowMut<T> for T
where T: ?Sized,

源代码§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. 更多信息
源代码§

impl<T> From<!> for T

源代码§

fn from(t: !) -> T

从输入类型转换为此类型。
源代码§

impl<T> From<T> for T

源代码§

fn from(t: T) -> T

原样返回参数。

源代码§

impl<T, U> Into<U> for T
where U: From<T>,

源代码§

fn into(self) -> U

调用 U::from(self)

也就是说,此转换是 From<T> for U 实现选择执行的操作。

源代码§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

源代码§

type Error = Infallible

转换出错时返回的类型。
源代码§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

执行转换。
源代码§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

源代码§

type Error = <U as TryFrom<T>>::Error

转换出错时返回的类型。
源代码§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

执行转换。