Rust中多线程固定位置写入同一数组的实现问题
解决多线程写入数组固定位置的问题
你的代码存在三个核心问题:
- 变量克隆错误:
shared_j_copy错误克隆了shared_array,导致它的类型是Arc<Mutex<[i32;10]>>,而非你需要的Arc<Mutex<usize>>,直接引发后续类型不匹配错误。 - MutexGuard使用错误:调用
lock()后得到的MutexGuard是智能指针,不能直接作为数组索引,也不能直接对它执行+=操作,必须解引用获取内部实际值。 - 锁的持有时机不合理:如果在持有锁的状态下执行耗时操作,会导致其他线程阻塞,完全失去并行执行的意义。
修正后的基础版本代码
先解决这些错误,让代码正常运行:
use std::thread; use std::time::Duration; use std::sync::{Arc, Mutex}; fn main(){ let shared_array = Arc::new(Mutex::new([0;10])); let shared_j = Arc::new(Mutex::new(0 as usize)); let mut handles = vec![]; for _ in 0..10 { // 正确克隆对应的共享变量 let array_clone = shared_array.clone(); let j_clone = shared_j.clone(); let handle = thread::spawn(move || { // 先获取并递增索引,立即释放锁 let mut j_guard = j_clone.lock().unwrap(); let index = *j_guard; *j_guard += 1; drop(j_guard); // 手动释放锁,避免持有锁执行耗时操作 // 模拟耗时操作 thread::sleep(Duration::from_millis(1000)); // 写入数组对应位置 let mut tab = array_clone.lock().unwrap(); println!("写入 tab[{}]", index); tab[index] = index as i32; }); handles.push(handle); } // 等待所有线程完成,替代sleep的不精确方式 for handle in handles { handle.join().unwrap(); } let tab = shared_array.lock().unwrap(); println!("tab= {:?}", tab); }
更优方案:直接分配固定索引
你完全不需要共享的索引变量,循环本身可以直接给每个线程分配固定的索引位置,既避免锁竞争,代码也更简洁:
use std::thread; use std::time::Duration; use std::sync::{Arc, Mutex}; fn main(){ let shared_array = Arc::new(Mutex::new([0;10])); let mut handles = vec![]; // 直接在循环中给每个线程分配固定索引 for index in 0..10 { let array_clone = shared_array.clone(); let handle = thread::spawn(move || { // 模拟你的400行耗时操作 thread::sleep(Duration::from_millis(1000)); // 写入对应位置 let mut tab = array_clone.lock().unwrap(); println!("写入 tab[{}]", index); tab[index] = index as i32; }); handles.push(handle); } // 等待所有线程完成 for handle in handles { handle.join().unwrap(); } let tab = shared_array.lock().unwrap(); println!("tab= {:?}", tab); }
方案说明
- 直接分配固定索引的方式彻底避免了锁竞争,性能更高。
- 使用
join()等待所有线程完成,比sleep()更可靠,不会因为耗时操作实际时间超过sleep时长导致结果未写入完成。 - 耗时操作放在锁外面,只在写入数组的瞬间持有锁,最大程度保证并行效率。
内容的提问来源于stack exchange,提问作者curious coder
相关产品推荐
相关产品推荐

