面试题答案
一键面试Condvar
与Mutex
协同工作原理:Mutex
:用于保护共享资源,确保同一时间只有一个线程可以访问共享资源,防止数据竞争。在Rust中,Mutex
通过lock
方法获取锁,获取成功后才能访问其内部的数据。Condvar
:条件变量依赖于Mutex
工作,用于线程间的同步和通信。它允许线程在满足特定条件时被唤醒,从而避免不必要的轮询。Condvar
主要有wait
和notify
系列方法。wait
方法会释放其关联的Mutex
锁,并阻塞当前线程,直到被其他线程通过notify
唤醒,唤醒后会重新获取Mutex
锁。notify_one
唤醒一个等待在条件变量上的线程,notify_all
唤醒所有等待在条件变量上的线程。
- 生产者 - 消费者模型示例:
use std::sync::{Arc, Condvar, Mutex};
use std::thread;
struct SharedQueue<T> {
queue: Vec<T>,
capacity: usize,
}
impl<T> SharedQueue<T> {
fn new(capacity: usize) -> Self {
SharedQueue {
queue: Vec::with_capacity(capacity),
capacity,
}
}
fn push(&mut self, item: T) {
self.queue.push(item);
}
fn pop(&mut self) -> Option<T> {
self.queue.pop()
}
}
fn main() {
let shared_queue = Arc::new((Mutex::new(SharedQueue::<i32>::new(5)), Condvar::new()));
let producer_shared_queue = shared_queue.clone();
let consumer_shared_queue = shared_queue.clone();
let producer = thread::spawn(move || {
for i in 0..10 {
let (queue_mutex, condvar) = &*producer_shared_queue;
let mut queue = queue_mutex.lock().unwrap();
while queue.queue.len() == queue.capacity {
queue = condvar.wait(queue).unwrap();
}
queue.push(i);
println!("Producer produced: {}", i);
condvar.notify_one();
}
});
let consumer = thread::spawn(move || {
for _ in 0..10 {
let (queue_mutex, condvar) = &*consumer_shared_queue;
let mut queue = queue_mutex.lock().unwrap();
while queue.queue.is_empty() {
queue = condvar.wait(queue).unwrap();
}
if let Some(item) = queue.pop() {
println!("Consumer consumed: {}", item);
condvar.notify_one();
}
}
});
producer.join().unwrap();
consumer.join().unwrap();
}
在上述代码中:
- 生产者线程获取
Mutex
锁后,检查共享队列是否已满,如果已满则调用Condvar
的wait
方法,释放Mutex
锁并等待被唤醒。当被唤醒后重新获取Mutex
锁,将数据放入队列,并调用notify_one
唤醒一个等待的消费者线程。 - 消费者线程获取
Mutex
锁后,检查共享队列是否为空,如果为空则调用Condvar
的wait
方法,释放Mutex
锁并等待被唤醒。当被唤醒后重新获取Mutex
锁,从队列中取出数据,并调用notify_one
唤醒一个等待的生产者线程。通过Mutex
保护共享队列,通过Condvar
实现生产者和消费者线程之间的同步,确保数据的正确传递并避免竞争条件。