MST

星途 面试题库

面试题:Rust中条件变量如何与互斥锁协同工作

在Rust中,描述条件变量(`Condvar`)与互斥锁(`Mutex`)是怎样协同工作来实现并发协调的?请举例说明,假设你有一个生产者 - 消费者模型,生产者生产数据放入一个共享队列,消费者从队列中取出数据,如何使用条件变量和互斥锁来确保数据的正确传递且避免竞争条件。
48.2万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试
  1. CondvarMutex 协同工作原理
    • Mutex:用于保护共享资源,确保同一时间只有一个线程可以访问共享资源,防止数据竞争。在Rust中,Mutex 通过 lock 方法获取锁,获取成功后才能访问其内部的数据。
    • Condvar:条件变量依赖于 Mutex 工作,用于线程间的同步和通信。它允许线程在满足特定条件时被唤醒,从而避免不必要的轮询。Condvar 主要有 waitnotify 系列方法。wait 方法会释放其关联的 Mutex 锁,并阻塞当前线程,直到被其他线程通过 notify 唤醒,唤醒后会重新获取 Mutex 锁。notify_one 唤醒一个等待在条件变量上的线程,notify_all 唤醒所有等待在条件变量上的线程。
  2. 生产者 - 消费者模型示例
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 锁后,检查共享队列是否已满,如果已满则调用 Condvarwait 方法,释放 Mutex 锁并等待被唤醒。当被唤醒后重新获取 Mutex 锁,将数据放入队列,并调用 notify_one 唤醒一个等待的消费者线程。
  • 消费者线程获取 Mutex 锁后,检查共享队列是否为空,如果为空则调用 Condvarwait 方法,释放 Mutex 锁并等待被唤醒。当被唤醒后重新获取 Mutex 锁,从队列中取出数据,并调用 notify_one 唤醒一个等待的生产者线程。通过 Mutex 保护共享队列,通过 Condvar 实现生产者和消费者线程之间的同步,确保数据的正确传递并避免竞争条件。