MST

星途 面试题库

面试题:Rust并发编程中的条件变量应用

假设你正在使用Rust编写一个多线程程序,其中一个线程负责生成数据,多个线程负责消费数据。请描述如何使用条件变量(`Condvar`)来协调线程之间的同步,以避免生产者 - 消费者模型中的常见问题,如数据竞争和死锁。同时给出实现这一模型的代码示例,并详细解释每个关键部分的作用。
26.5万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

1. 条件变量(Condvar)的作用

在生产者 - 消费者模型中,Condvar 用于协调线程之间的同步。它允许一个线程(生产者)通知其他线程(消费者)有新的数据可用,同时让消费者线程在没有数据时等待,避免无效的忙碌等待,从而防止数据竞争和死锁。

2. 代码示例

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

fn main() {
    let shared_data = Arc::new((Mutex::new(None), Condvar::new()));
    let producer_shared_data = shared_data.clone();

    // 生产者线程
    let producer = thread::spawn(move || {
        for i in 0..10 {
            let (lock, cvar) = &*producer_shared_data;
            let mut data = lock.lock().unwrap();
            *data = Some(i);
            println!("Produced: {}", i);
            data = cvar.notify_one().unwrap();
        }
    });

    let consumer_shared_data = shared_data.clone();
    // 消费者线程
    let consumer = thread::spawn(move || {
        let (lock, cvar) = &*consumer_shared_data;
        loop {
            let mut data = lock.lock().unwrap();
            while data.is_none() {
                data = cvar.wait(data).unwrap();
            }
            let value = data.take().unwrap();
            println!("Consumed: {}", value);
            if value == 9 {
                break;
            }
        }
    });

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

3. 关键部分解释

  • Arc<(Mutex<Option<i32>>, Condvar)>
    • Arc 用于在多个线程间共享数据,因为它允许线程安全地克隆指针。
    • Mutex 用于保护共享数据(这里是 Option<i32>),确保同一时间只有一个线程可以访问数据,防止数据竞争。
    • Condvar 用于线程间的同步通知,让消费者线程在没有数据时等待,生产者线程有数据时通知消费者。
  • 生产者线程
    • let mut data = lock.lock().unwrap();:获取锁,进入临界区,确保对共享数据的独占访问。
    • *data = Some(i);:生成数据并放入共享变量。
    • data = cvar.notify_one().unwrap();:通知一个等待在条件变量上的消费者线程有新数据可用。
  • 消费者线程
    • let mut data = lock.lock().unwrap();:获取锁,进入临界区。
    • while data.is_none() { data = cvar.wait(data).unwrap(); }:如果没有数据,释放锁并等待在条件变量上,当收到通知后重新获取锁并检查数据。
    • let value = data.take().unwrap();:取出并消费数据。
    • if value == 9 { break; }:当消费完最后一个数据后,退出循环。
  • join 操作
    • producer.join().unwrap();consumer.join().unwrap(); 等待生产者和消费者线程完成,确保主线程不会提前退出。