面临的挑战
- 线程安全:虽然 Rust 中的不可变数据在单线程中是安全的,但在多线程环境下,多个线程同时访问不可变数据时,可能会出现线程安全问题。例如,如果多个线程同时读取不可变数据,而数据的读取操作不是原子的,可能会导致数据不一致。
- 数据竞争:尽管不可变数据通常不会发生数据竞争(因为没有线程可以修改它),但如果在共享不可变数据的同时,存在对数据内部状态的隐式修改(例如,通过内部可变性模式),仍然可能发生数据竞争。
解决方案
- 使用
Arc
和 Mutex
:Arc
(原子引用计数)用于在多个线程间共享数据,Mutex
(互斥锁)用于保证同一时间只有一个线程可以访问数据。
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let data = Arc::new(Mutex::new(42));
let mut handles = vec![];
for _ in 0..10 {
let data_clone = Arc::clone(&data);
let handle = thread::spawn(move || {
let mut num = data_clone.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Final value: {}", *data.lock().unwrap());
}
- 使用
RwLock
:RwLock
(读写锁)允许多个线程同时读取数据,但只允许一个线程写入数据。这在读取操作远多于写入操作的场景下非常有用。
use std::sync::{Arc, RwLock};
use std::thread;
fn main() {
let data = Arc::new(RwLock::new(42));
let mut handles = vec![];
for _ in 0..5 {
let data_clone = Arc::clone(&data);
let handle = thread::spawn(move || {
let num = data_clone.read().unwrap();
println!("Read value: {}", num);
});
handles.push(handle);
}
for _ in 0..2 {
let data_clone = Arc::clone(&data);
let handle = thread::spawn(move || {
let mut num = data_clone.write().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Final value: {}", *data.read().unwrap());
}