- 使用
Mutex
(互斥锁)
- 策略阐述:
Mutex
用于保护共享数据,每次只允许一个线程访问共享数据。当一个线程想要访问共享数据时,它必须先获取 Mutex
的锁。如果锁已被其他线程持有,该线程会被阻塞,直到锁被释放。
- Rust 标准库工具:在 Rust 标准库中,
std::sync::Mutex
提供了互斥锁功能。例如:
use std::sync::{Arc, Mutex};
use std::thread;
let data = Arc::new(Mutex::new(0));
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();
}
let final_num = data.lock().unwrap();
println!("Final value: {}", *final_num);
- 使用
RwLock
(读写锁)
- 策略阐述:当读操作远远多于写操作时,
RwLock
是一个更好的选择。它允许多个线程同时进行读操作,但只允许一个线程进行写操作。写操作时,会独占锁,阻止其他读和写操作。读操作时,如果没有写操作正在进行,多个读线程可以同时获取锁进行读取。
- Rust 标准库工具:
std::sync::RwLock
实现了读写锁功能。示例如下:
use std::sync::{Arc, RwLock};
use std::thread;
let data = Arc::new(RwLock::new(0));
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);
}
let write_handle = thread::spawn(move || {
let mut num = data.write().unwrap();
*num += 1;
});
write_handle.join().unwrap();
for handle in handles {
handle.join().unwrap();
}
- 使用
Atomic
类型
- 策略阐述:对于简单的共享数据类型(如整数、布尔值等),可以使用
Atomic
类型。这些类型提供了原子操作,不需要像 Mutex
或 RwLock
那样进行锁操作,从而避免了锁竞争带来的开销。原子操作是不可中断的,保证了数据一致性。
- Rust 标准库工具:
std::sync::atomic
模块提供了各种 Atomic
类型,如 AtomicI32
、AtomicBool
等。例如:
use std::sync::atomic::{AtomicI32, Ordering};
use std::thread;
let data = AtomicI32::new(0);
let mut handles = vec![];
for _ in 0..10 {
let data_clone = data.clone();
let handle = thread::spawn(move || {
data_clone.fetch_add(1, Ordering::SeqCst);
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Final value: {}", data.load(Ordering::SeqCst));
- 通道(
channel
)和 mpsc
(多生产者单消费者)
- 策略阐述:通过通道在不同线程间传递数据,而不是直接共享数据。发送端线程将数据发送到通道,接收端线程从通道接收数据。这种方式可以避免多个线程直接访问和修改共享数据,从而保证数据一致性。
- Rust 标准库工具:
std::sync::mpsc
模块提供了多生产者单消费者通道。示例如下:
use std::sync::mpsc;
use std::thread;
let (tx, rx) = mpsc::channel();
let mut handles = vec![];
for _ in 0..10 {
let tx_clone = tx.clone();
let handle = thread::spawn(move || {
tx_clone.send(1).unwrap();
});
handles.push(handle);
}
drop(tx);
let sum: i32 = rx.iter().sum();
for handle in handles {
handle.join().unwrap();
}
println!("Sum: {}", sum);