#events #mpmc #oneshot #sync #async

triggered

在任务和线程之间触发一次性事件

3 个版本

0.1.2 2021年7月19日
0.1.1 2020年5月1日
0.1.0 2020年4月20日

异步 中排名第 83

Download history 9916/week @ 2024-03-14 11217/week @ 2024-03-21 8784/week @ 2024-03-28 8072/week @ 2024-04-04 9628/week @ 2024-04-11 8813/week @ 2024-04-18 11472/week @ 2024-04-25 12210/week @ 2024-05-02 9747/week @ 2024-05-09 11256/week @ 2024-05-16 16392/week @ 2024-05-23 13316/week @ 2024-05-30 11989/week @ 2024-06-06 15795/week @ 2024-06-13 14115/week @ 2024-06-20 9759/week @ 2024-06-27

每月下载量 53,611
87crate(直接使用 28 个)中使用

MIT/Apache

19KB
187

triggered

任务和线程之间的一次性事件触发器。

该机制由两种类型组成,即 TriggerListener。它们作为一对出现。就像通道的发送者/接收者对一样。触发器部分有一个 Trigger::trigger 方法,将使所有等待监听器的任务/线程继续执行。监听器既有同步的 Listener::wait 方法,也实现了 Future<Output = ()> 以支持异步。

TriggerListener 都可以克隆。所以任何数量的触发器实例都可以触发任何数量的等待监听器。当任何一对触发器实例被触发时,所有等待的监听器都将被解除阻塞。等待已经触发的触发器的监听器将立即返回。因此,每个触发器/监听器对只能触发一次。

此crate不使用任何 unsafe 代码。

示例

一个简单的示例,展示基本用法

#[tokio::main]
async fn main() {
    let (trigger, listener) = triggered::trigger();

    let task = tokio::spawn(async {
        // Blocks until `trigger.trigger()` below
        listener.await;

        println!("Triggered async task");
    });

    // This will make any thread blocked in `Listener::wait()` or async task awaiting the
    // listener continue execution again.
    trigger.trigger();

    let _ = task.await;
}

一个示例,展示如何使用触发器/监听器对,在Ctrl-C事件上优雅地关闭一些异步服务器实例,其中只接受不可变的 Fn 闭包


#[tokio::main]
async fn main() -> Result<(), Error> {
    let (shutdown_trigger, shutdown_signal1) = triggered::trigger();

    // A sync `Fn` closure will trigger the trigger when the user hits Ctrl-C
    ctrlc::set_handler(move || {
        shutdown_trigger.trigger();
    }).expect("Error setting Ctrl-C handler");

    // If the server library has support for something like a shutdown signal:
    let shutdown_signal2 = shutdown_signal1.clone();
    let server1_task = tokio::spawn(async move {
        SomeServer::new().serve_with_shutdown_signal(shutdown_signal1).await;
    });

    // Or just select between the long running future and the signal to abort it
    tokio::select! {
        server_result = SomeServer::new().serve() => {
            eprintln!("Server error: {:?}", server_result);
        }
        _ = shutdown_signal2 => {}
    }

    let _ = server1_task.await;
    Ok(())
}

Rust 兼容性

将至少与最新的两个稳定Rust版本兼容。这使用户在新稳定版发布后至少有六周的时间来升级他们的Rust工具链。

当前的MSRV可以在 travis.yml 中看到。任何对MSRV的更改都将被视为破坏性更改并列入 变更日志

与类似原语的比较

通道

本库中的事件触发原语与通道有些相似。主要区别和开发此库的原因是

监听器与 futures::channel::oneshot::Receiver<()> 类似。但它

  • 不可失败 - 实现了 Future<Output = ()> 而不是 Future<Output = Result<T, Canceled>>
  • 实现了 Clone - 任意数量的监听器可以等待同一事件
  • 有一个同步的 Listener::wait - 同步线程和异步任务可以同时等待。

触发器与 futures::channel::oneshot::Sender<()> 相比有以下不同之处

  • 不可失败 - 触发器不考虑是否有监听器剩下
  • 发送时不会消耗自身,而是取 &self - 因此可以在不是所有者或不可变的情况下使用。例如在 Drop 实现或限于 FnFnMut 的回调闭包中。

futures::future::可取消

这些触发器的一个用例是在某些事件发生时取消future。请参见上面的示例。区别包括

  • 单个句柄可以取消任何数量的future
  • 有些future在仅通过Abortable丢弃时并没有得到适当的清理。这些库有时允许使用带有关闭信号的future来触发干净的取消。类似于 serve_with_shutdown(signal: impl Future<Output = ()>)

无运行时依赖