Rust线程并行与共享资源更新疑问:Mutex为何未按预期解锁?
为什么Rust中Mutex保护的线程会连续执行完所有迭代?
你的代码核心问题是Mutex锁的作用域过大。每个线程的循环中,lock()返回的MutexGuard(也就是代码里的num)作用域覆盖了整个循环体——从获取锁开始,到sleep、println执行完毕,num才会离开作用域,Mutex才会被解锁。
这意味着线程拿到锁后,会持有它整整一次迭代的时间:包括修改计数器、sleep 10毫秒、打印内容。在sleep的10毫秒里,锁依然被当前线程攥着,其他线程完全无法获取Mutex,只能原地等待。而当前线程解锁后,会立刻进入下一次循环再次抢锁——操作系统通常会优先调度刚刚释放锁的线程,所以它能反复抢到锁,直到跑完所有5次迭代,才会轮到其他线程执行。
修复方案:缩小锁的作用域
把锁的持有范围严格限制在仅修改计数器的阶段,修改完成后立刻释放锁,让其他线程有机会获取锁。
优化后的代码(保存修改后的值避免重复加锁)
use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; fn main() { let counter = Arc::new(Mutex::new(0)); let counter_clone1 = Arc::clone(&counter); let t1 = thread::spawn(move || { for _ in 0..5 { // 仅在修改计数器时持有锁,修改完成后立即释放 let current_val = { let mut num = counter_clone1.lock().unwrap(); *num += 1; *num // 返回当前值,代码块结束后num被drop,Mutex解锁 }; thread::sleep(Duration::from_millis(10)); println!("printing from the thread 1 value --> {}", current_val); } }); let counter_clone2 = Arc::clone(&counter); let t2 = thread::spawn(move || { for _ in 0..5 { let current_val = { let mut num = counter_clone2.lock().unwrap(); *num += 1; *num }; thread::sleep(Duration::from_millis(10)); println!("printing from the thread 2 value --> {}", current_val); } }); let counter_clone3 = Arc::clone(&counter); let t3 = thread::spawn(move || { for _ in 0..5 { let current_val = { let mut num = counter_clone3.lock().unwrap(); *num += 1; *num }; thread::sleep(Duration::from_millis(10)); println!("printing from the thread 3 value --> {}", current_val); } }); t1.join().unwrap(); t2.join().unwrap(); t3.join().unwrap(); println!("final value of counter --> {}", counter.lock().unwrap()); }
修改后,每个线程修改完计数器就立刻释放锁,sleep和打印时锁处于自由状态,其他线程可以随时获取锁修改计数器,就能得到你预期的线程交替执行的输出效果。
内容的提问来源于stack exchange,提问作者Soumyajit Roy
相关产品推荐
相关产品推荐

