MST

星途 面试题库

面试题:Rust线程停放:复杂场景与同步

在一个多线程的Rust程序中,有多个线程需要协同工作,其中部分线程可能需要根据特定条件进行停放和唤醒。假设存在共享资源,如何通过Rust的线程停放机制结合同步原语(如`Mutex`或`RwLock`)来确保线程安全,并高效地实现线程间的协作,避免死锁?请给出具体的代码示例及解释。
38.7万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试
use std::sync::{Arc, Condvar, Mutex};
use std::thread;

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

    // 线程1,用于检查条件并唤醒线程2
    let thread1 = thread::spawn(move || {
        let (lock, cvar) = &*shared_data_clone;
        let mut data = lock.lock().unwrap();
        *data = true;
        println!("线程1设置条件为true");
        // 唤醒所有等待的线程
        cvar.notify_all();
    });

    // 线程2,等待条件满足
    let thread2 = thread::spawn(move || {
        let (lock, cvar) = &*shared_data;
        let mut data = lock.lock().unwrap();
        while!*data {
            println!("线程2等待条件...");
            data = cvar.wait(data).unwrap();
        }
        println!("线程2条件满足,继续执行");
    });

    thread1.join().unwrap();
    thread2.join().unwrap();
}

代码解释

  1. 同步原语定义
    • Arc(原子引用计数)用于在多个线程间共享数据。这里共享的是一个元组,包含一个Mutex和一个Condvar
    • Mutex(互斥锁)用于保护共享数据,确保同一时间只有一个线程可以访问。
    • Condvar(条件变量)用于线程的停放和唤醒。
  2. 线程1
    • 获取Mutex的锁,并将共享数据设置为true
    • 调用Condvarnotify_all方法,唤醒所有等待在这个条件变量上的线程。
  3. 线程2
    • 获取Mutex的锁,并通过while循环检查共享数据。
    • 如果共享数据为false,则调用Condvarwait方法,释放Mutex锁并停放线程。当被唤醒时,wait方法重新获取Mutex锁并返回。
  4. 主函数
    • 创建并启动两个线程thread1thread2
    • 调用join方法等待两个线程执行完毕,确保主线程不会提前退出。

避免死锁的措施

  1. 合理的锁获取顺序:在这个示例中,两个线程获取锁的顺序是一致的,都是先获取Mutex锁。如果多个线程需要获取多个锁,确保所有线程以相同的顺序获取锁,可以避免死锁。
  2. 条件变量的正确使用Condvarwait方法在等待时会释放Mutex锁,避免了等待过程中一直持有锁导致其他线程无法获取锁的情况,从而防止死锁。同时,notify_all方法确保等待的线程能够被唤醒,继续执行。