面试题答案
一键面试1. Mutex与Condvar协同工作的场景
当多个线程需要访问共享资源,并且在某些条件满足时才进行操作时,Mutex与Condvar协同工作非常有用。例如,在生产者 - 消费者模型中,消费者线程需要等待生产者线程向共享队列中添加数据后才能消费。
2. 实现方式
use std::sync::{Arc, Condvar, Mutex};
fn main() {
let shared_data = Arc::new((Mutex::new(0), Condvar::new()));
let shared_data_clone = shared_data.clone();
std::thread::spawn(move || {
let (data, cvar) = &*shared_data_clone;
let mut num = data.lock().unwrap();
*num = 42;
cvar.notify_one();
});
let (data, cvar) = &*shared_data;
let mut num = data.lock().unwrap();
while *num == 0 {
num = cvar.wait(num).unwrap();
}
println!("Got value: {}", num);
}
- Mutex:用于保护共享数据的访问,确保同一时间只有一个线程可以修改共享数据。
- Condvar:用于线程间的通信,让线程在某个条件满足时被唤醒。
3. Rust内存模型保证数据一致性和线程安全性
- 所有权与借用:Rust的所有权系统确保在编译时就检查数据的访问权限,避免数据竞争。在上述代码中,
Mutex
通过内部可变性来打破所有权规则,但它的lock
方法会限制同一时间只有一个线程能获取锁,从而访问共享数据。 - 内存屏障:
- 获取锁:当一个线程调用
Mutex::lock
获取锁时,会有一个内存屏障操作。这个内存屏障确保在获取锁之前,所有对共享数据的写操作都对其他线程可见,并且在获取锁之后的读操作能够读取到最新的数据。 - 释放锁:当线程调用
Mutex::unlock
释放锁时,也会有一个内存屏障操作。这个屏障确保在释放锁之前对共享数据的所有写操作对其他线程可见,从而保证数据一致性。 - 条件变量:
Condvar::wait
方法会自动释放Mutex
锁并阻塞线程,当被唤醒时,会重新获取Mutex
锁。在这个过程中,同样会有内存屏障操作,确保在等待期间对共享数据的任何修改在唤醒后都能被正确读取。
- 获取锁:当一个线程调用
通过这些机制,Rust的内存模型保证了在Mutex与Condvar协同工作时的数据一致性和线程安全性。