MST

星途 面试题库

面试题:Rust互斥与其他并发原语的协同及内存模型

在Rust中,Mutex常常与其他并发原语(如Condvar、RwLock等)协同使用。请描述Mutex与Condvar协同工作的场景及实现方式,并深入分析在这种协同工作中,Rust的内存模型是如何保证数据一致性和线程安全性的,包括内存屏障等底层机制的作用。
36.5万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

1. Mutex与Condvar协同工作的场景

当多个线程需要访问共享资源,并且在某些条件满足时才进行操作时,Mutex与Condvar协同工作非常有用。例如,在生产者 - 消费者模型中,消费者线程需要等待生产者线程向共享队列中添加数据后才能消费。

2. 实现方式

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

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

    std::thread::spawn(move || {
        let (data, cvar) = &*shared_data_clone;
        let mut num = data.lock().unwrap();
        *num = 42;
        cvar.notify_one();
    });

    let (data, cvar) = &*shared_data;
    let mut num = data.lock().unwrap();
    while *num == 0 {
        num = cvar.wait(num).unwrap();
    }
    println!("Got value: {}", num);
}
  • Mutex:用于保护共享数据的访问,确保同一时间只有一个线程可以修改共享数据。
  • Condvar:用于线程间的通信,让线程在某个条件满足时被唤醒。

3. Rust内存模型保证数据一致性和线程安全性

  • 所有权与借用:Rust的所有权系统确保在编译时就检查数据的访问权限,避免数据竞争。在上述代码中,Mutex通过内部可变性来打破所有权规则,但它的lock方法会限制同一时间只有一个线程能获取锁,从而访问共享数据。
  • 内存屏障
    • 获取锁:当一个线程调用Mutex::lock获取锁时,会有一个内存屏障操作。这个内存屏障确保在获取锁之前,所有对共享数据的写操作都对其他线程可见,并且在获取锁之后的读操作能够读取到最新的数据。
    • 释放锁:当线程调用Mutex::unlock释放锁时,也会有一个内存屏障操作。这个屏障确保在释放锁之前对共享数据的所有写操作对其他线程可见,从而保证数据一致性。
    • 条件变量Condvar::wait方法会自动释放Mutex锁并阻塞线程,当被唤醒时,会重新获取Mutex锁。在这个过程中,同样会有内存屏障操作,确保在等待期间对共享数据的任何修改在唤醒后都能被正确读取。

通过这些机制,Rust的内存模型保证了在Mutex与Condvar协同工作时的数据一致性和线程安全性。