MST

星途 面试题库

面试题:Rust互斥锁与条件变量的协作

在Rust中,如何使用互斥锁和条件变量来实现生产者 - 消费者模型?请详细描述实现思路,并给出关键代码片段。同时说明在这种场景下,如何处理死锁和虚假唤醒等问题。
22.5万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 互斥锁(Mutex):用于保护共享资源,确保同一时间只有一个线程可以访问共享资源。在生产者 - 消费者模型中,共享资源可能是一个缓冲区。
  2. 条件变量(Condvar):用于线程间的通信。生产者线程在缓冲区有空间时通知消费者线程,消费者线程在缓冲区有数据时通知生产者线程。
  3. 生产者:生产数据,获取互斥锁,将数据放入共享缓冲区,然后通知等待的消费者线程。
  4. 消费者:获取互斥锁,检查共享缓冲区是否有数据,若没有则等待条件变量通知,有数据则取出并消费。

关键代码片段

use std::sync::{Arc, Mutex, Condvar};
use std::thread;

fn main() {
    let shared_data = Arc::new((Mutex::new(Vec::new()), Condvar::new()));
    let producer_shared = shared_data.clone();
    let consumer_shared = shared_data.clone();

    let producer = thread::spawn(move || {
        for i in 0..10 {
            let (lock, cvar) = &*producer_shared;
            let mut data = lock.lock().unwrap();
            data.push(i);
            println!("Produced: {}", i);
            drop(data);
            cvar.notify_one();
        }
    });

    let consumer = thread::spawn(move || {
        let (lock, cvar) = &*consumer_shared;
        for _ in 0..10 {
            let mut data = lock.lock().unwrap();
            while data.is_empty() {
                data = cvar.wait(data).unwrap();
            }
            let item = data.pop().unwrap();
            println!("Consumed: {}", item);
        }
    });

    producer.join().unwrap();
    consumer.join().unwrap();
}

处理死锁问题

  1. 按顺序获取锁:确保所有线程以相同顺序获取锁,避免循环依赖。在生产者 - 消费者模型中,只有一个互斥锁,所以这方面不容易出现死锁,但如果有多个锁(例如多个缓冲区),要注意获取顺序。
  2. 避免嵌套锁:尽量减少锁的嵌套使用,以降低死锁风险。
  3. 使用超时机制:在获取锁时设置超时,若在规定时间内未获取到锁,则放弃操作并释放已获取的锁,如使用try_lock方法并结合std::time::Duration设置超时。

处理虚假唤醒问题

  1. 使用循环检查条件:在消费者线程等待条件变量通知后,使用循环再次检查共享缓冲区是否真的有数据,而不是直接假设通知一定意味着缓冲区有数据。如上述代码中while data.is_empty() { data = cvar.wait(data).unwrap(); },这样即使出现虚假唤醒,也会再次等待直到条件满足。