5 个版本 (2 个稳定版)

1.0.1 2024年2月20日
1.0.0 2022年11月3日
0.2.2 2022年3月27日
0.2.1 2022年3月27日
0.1.0 2021年7月5日

#42并发

Download history 6320/week @ 2024-05-01 7016/week @ 2024-05-08 7595/week @ 2024-05-15 4920/week @ 2024-05-22 8049/week @ 2024-05-29 7820/week @ 2024-06-05 7653/week @ 2024-06-12 8638/week @ 2024-06-19 5832/week @ 2024-06-26 6765/week @ 2024-07-03 7723/week @ 2024-07-10 8937/week @ 2024-07-17 9645/week @ 2024-07-24 9885/week @ 2024-07-31 7355/week @ 2024-08-07 7783/week @ 2024-08-14

36,460 每月下载量
用于 7 个 Crates (2 个直接使用)

GPL-3.0 或更新

68KB
1K SLoC

async-condvar-fair

异步 Rust 的条件变量。特性

  • 公平的。 notify_one 总是唤醒等待时间最长的等待者。

  • 新颖的 Baton 功能,帮助避免异步任务取消时可能出现的通知丢失。

  • 适用于任何异步运行时。

  • 可以与任何类型的互斥锁(同步或异步)一起工作。

  • 100% 安全的代码。 (内部使用 parking_lotdlv-list。)

  • 可以处理多个不同互斥锁与多个不同条件变量的交互,如果您喜欢这种类型的话。

主入口点

此库的主入口点是 Condvar。请参阅其文档以了解构造函数和方法详情。

示例

// async-condvar-fair = { version = "0.2", features = "parking_lot_0_12" }
// parking_lot = { version = "0.12", features = ["send_guard"] }
# #[cfg(feature = "parking_lot_0_12")] mod demo {
use std::collections::VecDeque;
use async_condvar_fair::{Condvar, BatonExt};
use parking_lot::Mutex;

struct Shared {
    cv: Condvar,
    queue: Mutex<VecDeque<String>>,
}

impl Shared {
    pub async fn procssor(&self) {
        let mut guard = self.queue.lock();
        let mut baton = None;
        loop {
            while let Some(entry) = guard.pop_front() {
                println!("processing {:?}", &entry);
            }
            baton.dispose();

            let got = self.cv.wait_baton(guard).await;
            guard = got.0;
            baton = got.1;
        }
    }
}
# }

互斥锁 - 选择互斥锁,同步与异步

请注意,可以拥有异步条件变量,但使用同步互斥锁来保护共享状态。如果持有互斥锁期间的操作很快(特别是不执行 I/O),这通常是最佳选择。

parking_lot::Mutex 是此类同步互斥锁的一个好选择,并且由 async-condvar-fair 方便地支持。您可能需要启用 parking_lotsend_guard 功能。

如果您使用同步互斥锁,您可能不打算在持有互斥锁时等待,因此您可能可以使用普通的 wait (而不是 wait_baton)。

如果在持有互斥锁期间进行的操作很慢,您应该使用异步运行时提供的异步互斥锁。在这种情况下,如果您使用notify_one,您应该考虑使用wait_baton以避免任务取消导致丢失通知:请参阅Baton

互斥锁保护,线程间Send传输

在多线程异步运行时中,任务可以在线程之间移动。这意味着互斥锁保护需要是Send。多线程异步运行时提供的异步互斥锁保护都是Send。同步互斥锁保护通常不是。

例如,std::sync::MutexGuard,它只能与非多线程运行时的Condvar一起使用,因为具有这种保护器的局部变量的futures将不会是Send。相反,使用启用了send_guardparking_lot

互斥锁 - 如何将互斥锁传递给wait_baton

Condvar::wait_batonwait原则上可以与任何互斥锁一起工作。但它们需要知道如何重新锁定互斥锁。

对于最方便的互斥锁,如parking_lot::Mutex,您可以只需将保护器传递给wait。当唤醒时,Condvar将使用保护器来解锁互斥锁,然后再次重新锁定它。

但对于许多互斥锁,这是不可能的,因为保护器类型不提供获取解锁互斥锁引用的方式。例如,这是std::sync::Mutex的情况。

对于这些不便的互斥锁,您可以传递一个元组给wait_batonwait,或者使用wait_no_relock并自行重新锁定互斥锁。

内置互斥锁支持以及async-condvar-fair软件包功能

功能 互斥锁类型 传递给wait / wait_baton
始终启用 std::sync::Mutex (MutexGuard, &Mutex) [2]
parking_lot_N parking_lot::Mutex MutexGuard [1]
parking_lot_N parking_lot::FairMutex FairMutexGuard [1]
tokio tokio::sync::Mutex (MutexGuard, &Mutex)
tokio Arc<tokio::sync::Mutex> (OwnedMutexGuard, Arc<Mutex>)
tokio tokio::sync::RwLock (RwLockReadGuard, &Mutex)
tokio tokio::sync::RwLock (RwLockWriteGuard, &Mutex)
tokio Arc<tokio::sync::RwLock> (OwnedRwLockReadGuard, Arc<RwLock>)
tokio Arc<tokio::sync::RwLock> (OwnedRwLockWriteGuard, Arc<RwLock>)
smol smol::lock::Mutex MutexGuard
smol smol::lock::RwLock (RwLockReadGuard, &RwLock)
smol smol::lock::RwLock (RwLockWriteGuard, &RwLock)
smol Arc<smol::lock::Mutex> MutexGuardArc

注意:以下所有功能默认均未启用,因为每个功能都意味着对相应crate的依赖。

  1. 启用与您使用的 parking_lot 版本对应的 parking_lot_N 功能(在您的 Cargo.toml 中指定)。为使用多线程运行时启用 parking_lotsend_guard 功能。
  2. 仅限单线程运行时。

与其他互斥锁一起使用

上述支持都是通过提供的 RelockMutexGuard trait 的实现实现的。

如果您想使用在 async-condvar-wait 中没有内置支持的互斥锁类型,请使用 RelockMutexGuard! 宏来定义合适的实现,手动定义该实现,或使用 wait_no_relock 并自行重新锁定互斥锁。

传递守卫和互斥锁元组的示例

# fn main() {
# #[cfg(feature = "parking_lot_0_12")] {
# use std::collections::VecDeque;
# use async_condvar_fair::{Condvar, BatonExt};
use std::sync::Mutex;
struct Shared {
    cv: Condvar,
    queue: Mutex<VecDeque<String>>,
}
# 
# impl Shared {
#    pub async fn procssor(&self) {
#        let mut guard = self.queue.lock().unwrap();
#        let mut baton = None;
loop {
    while let Some(entry) = guard.pop_front() {
        println!("processing {:?}", &entry);
        if entry.is_empty() { break }
    }
    baton.dispose();

    let got = self.cv.wait_baton((guard, &self.queue)).await;
    guard = got.0;
    baton = got.1;
}
#    }
# } } }

变更日志 - 破坏性变更和重大错误修复

  • 1.0.1 2024-02-20:

    • 没有API或功能更改。
    • 放松 dlv-list 依赖(向上和向下)。
    • 明确声明我们的MSRV(1.56)。
    • 对文档的一些小修复。
    • 测试改进。
    • 将 Cargo.lock.example 重命名为 Cargo.lock。
  • 1.0.0 2022-10-11:

    • 将我们的版本更新到 1.x。
    • 增加 dlv-list 依赖。没有API或功能更改。
  • 0.2.2 2022-03-27:

    • 增加 dlv-list 依赖。没有API或功能更改。
  • 0.2.1 2022-03-27:

    • 破坏性变更:为提供特定 parking_lot 版本的 RelockMutexGuard 实现提供新的 parking_lot_N 功能。在从 0.1.0 升级时,指定新的功能 parking_lot_0_11
    • 支持 parking_lot 0.9、0.10、0.12。
  • 0.2.0:版本号未使用。

  • 0.1.0, 2021-07-05

    • 初始发布。

版权属于 Ian Jackson 和 Rust 软件包 async-condvar-fair 的贡献者。没有任何保证。请参阅源树中的 GPL-3LICENCE 文件。

SPDX-许可证-标识符: GPL-3.0--更新的

依赖关系

~0.6–14MB
~124K SLoC