如何在Rust Tokio异步任务间共享并修改u8变量
解决Tokio多任务共享变量并同步停止的问题
核心思路
要实现多任务共享可变状态,必须用Arc<Mutex<u8>>组合:
Arc让多个任务能同时持有同一数据的所有权(本质是引用计数,clone操作极轻量)Mutex保证同一时间只有一个任务能修改内部的计数器,彻底避免数据竞争
可运行的完整代码
use tokio::sync::Mutex; use std::sync::Arc; #[tokio::main] async fn main() { // 创建共享计数器:Arc包裹Mutex,内部存初始值0 let jobs_finished = Arc::new(Mutex::new(0u8)); // 给每个任务clone一份Arc实例——这是关键! let job1_counter = Arc::clone(&jobs_finished); let job2_counter = Arc::clone(&jobs_finished); let job3_counter = Arc::clone(&jobs_finished); // 任务1:循环检测计数器,等另外两个任务完成后停止 let task1 = tokio::spawn(async move { loop { // 异步锁定Mutex,读取当前计数 let count = *job1_counter.lock().await; if count >= 2 { println!("任务1:另外两个任务都完成了,我停了"); break; } // 加个短休眠,避免空转占CPU tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; } }); // 任务2:模拟耗时工作,完成后递增计数器 let task2 = tokio::spawn(async move { println!("任务2:启动干活"); tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; // 锁定Mutex并修改计数 let mut count = job2_counter.lock().await; *count += 1; println!("任务2:干完了,计数器现在是{}", *count); }); // 任务3:模拟耗时工作,完成后递增计数器 let task3 = tokio::spawn(async move { println!("任务3:启动干活"); tokio::time::sleep(tokio::time::Duration::from_secs(3)).await; let mut count = job3_counter.lock().await; *count += 1; println!("任务3:干完了,计数器现在是{}", *count); }); // 等待所有任务执行完毕 let _ = tokio::join!(task1, task2, task3); }
为什么你之前的代码跑不起来?
问题出在没有给第三个任务clone Arc:
- Rust的move语义会把原始Arc转移给前两个任务的闭包,导致第三个任务拿不到可用的引用
- 必须给每个任务单独clone一份Arc,这样每个闭包拿到的都是独立的引用计数指针,指向同一个Mutex和计数器
额外说明
如果只是单纯等待多个任务完成,用tokio::join!或者Barrier会更简洁,但你的核心需求是模拟多任务对变量的增改读,所以用Arc<Mutex>完全贴合场景。
内容的提问来源于stack exchange,提问作者Fabian Wagner - a6a2f5842
相关产品推荐
相关产品推荐

