寻求Tokio中支持事件预发生时无需等待的线程同步原语
解决方案:使用Tokio Watch通道
你的核心需求是实现一个一次性触发的事件同步原语,支持:
- 等待事件发生后继续执行
- 若事件已提前触发,无需等待直接通过
Tokio提供的watch通道是完全符合需求的标准解决方案,它专门用于单值的异步广播,天然支持“检查当前状态+等待更新”的语义,无需自行封装Mutex或原子变量。
示例代码
use std::sync::Arc; use tokio::sync::watch; #[tokio::main] async fn main() { // 创建watch通道,初始值标记事件未触发 let (tx, rx) = watch::channel(false); let rx1 = rx.clone(); let rx2 = rx.clone(); println!("sending notification"); // 触发事件:将通道值更新为true tx.send(true).unwrap(); // 第一个等待任务 let handle1 = tokio::spawn(async move { // wait_for会先检查当前值是否满足条件,满足则直接返回 // 不满足则等待值更新 rx1.wait_for(|&triggered| triggered).await.unwrap(); println!("received notification 1"); }); // 第二个等待任务 let handle2 = tokio::spawn(async move { rx2.wait_for(|&triggered| triggered).await.unwrap(); println!("received notification 2"); }); handle1.await.unwrap(); handle2.await.unwrap(); }
为什么这是地道方案?
- 状态持久化:Watch通道会保存最新的状态值,后续的等待者无需担心“错过提前触发的事件”
- 无竞态风险:内部已经封装了同步逻辑,无需手动处理Mutex/原子变量的内存顺序问题
- 异步友好:完全适配Tokio的异步 runtime,不会阻塞线程
为什么纯Notify不行?
Tokio的Notify是“唤醒当前等待者”的语义,当没有等待者时调用notify_waiters不会留下任何状态,后续调用notified().await会一直阻塞,这正是你遇到的问题。而Watch通道通过持久化状态解决了这个痛点。
内容的提问来源于stack exchange,提问作者Nikolay Zakirov
相关产品推荐
相关产品推荐

