- 使用
Mutex
和Arc
实现:
Mutex
(互斥锁)用于保护共享数据,确保同一时间只有一个线程可以访问和修改数据,从而避免数据竞争。
Arc
(原子引用计数)用于在多个线程间共享数据,因为Arc
允许在多个所有者之间共享数据,并且它是线程安全的。
- 代码示例:
use std::sync::{Arc, Mutex};
use std::thread;
// 定义一个包含可变字段的结构体
struct SharedData {
value: i32,
}
fn main() {
// 创建一个包含SharedData的Arc<Mutex<SharedData>>
let shared_data = Arc::new(Mutex::new(SharedData { value: 0 }));
let mut handles = vec![];
for _ in 0..10 {
// 克隆Arc,以便每个线程都有自己的引用
let data = Arc::clone(&shared_data);
let handle = thread::spawn(move || {
// 锁定Mutex以获取对数据的可变引用
let mut shared = data.lock().unwrap();
shared.value += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
// 打印最终结果
let result = shared_data.lock().unwrap();
println!("Final value: {}", result.value);
}
- 原理解释:
- 首先,我们定义了一个
SharedData
结构体,它包含一个可变字段value
。
- 然后,使用
Arc<Mutex<SharedData>>
来创建共享数据。Arc
允许在多个线程间共享Mutex<SharedData>
,而Mutex
确保对SharedData
的访问是线程安全的。
- 在每个线程中,通过
data.lock().unwrap()
来获取对SharedData
的可变引用。lock
方法会尝试获取锁,如果锁不可用,线程会阻塞直到锁可用。这里使用unwrap
是为了简单处理可能的错误(在实际生产中应该更优雅地处理Result
)。
- 最后,主线程等待所有子线程完成后,再次获取锁并打印最终的
value
值。由于Mutex
的保护,多个线程对value
的修改不会导致数据竞争,并且由于合理使用锁,也不会出现死锁(在这个简单示例中,没有出现死锁的场景,比如没有循环依赖锁的情况)。