MST

星途 面试题库

面试题:Rust中Mutex和RwLock的并发应用场景及实现细节

在Rust并发编程里,Mutex和RwLock都是用于线程同步的工具。请详细阐述Mutex和RwLock的应用场景,在什么情况下应该优先选择使用Mutex,什么情况下优先选择RwLock?并举例说明如何通过Rust的标准库实现一个线程安全的读写共享数据结构,要求代码体现Mutex和RwLock的合理使用。
24.2万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

Mutex应用场景

  • 应用场景:当需要对共享数据进行独占式访问时使用。比如共享数据结构的修改操作,在同一时刻只允许一个线程对其进行修改,防止数据竞争。
  • 优先选择情况:如果共享数据的读写操作都需要独占访问(即读操作也不允许并发),优先选择Mutex。例如银行账户余额的操作,无论是存款(写)还是查询余额(读),都需要防止其他线程同时操作,以保证数据一致性。

RwLock应用场景

  • 应用场景:适用于读多写少的场景。允许多个线程同时进行读操作,但写操作必须是独占的。因为读操作不会修改数据,所以多个线程同时读不会产生数据竞争。
  • 优先选择情况:当共享数据的读操作远远多于写操作时,优先选择RwLock。比如一个配置文件,启动时加载到内存,运行过程中读操作频繁,而写操作(修改配置)很少发生,这种场景适合用RwLock。

代码示例

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

// 使用Mutex实现线程安全的读写共享数据结构
struct SharedDataMutex {
    data: Mutex<i32>,
}

impl SharedDataMutex {
    fn new() -> Self {
        SharedDataMutex {
            data: Mutex::new(0),
        }
    }

    fn read(&self) -> i32 {
        *self.data.lock().unwrap()
    }

    fn write(&self, value: i32) {
        let mut guard = self.data.lock().unwrap();
        *guard = value;
    }
}

// 使用RwLock实现线程安全的读写共享数据结构
struct SharedDataRwLock {
    data: RwLock<i32>,
}

impl SharedDataRwLock {
    fn new() -> Self {
        SharedDataRwLock {
            data: RwLock::new(0),
        }
    }

    fn read(&self) -> i32 {
        *self.data.read().unwrap()
    }

    fn write(&self, value: i32) {
        let mut guard = self.data.write().unwrap();
        *guard = value;
    }
}

fn main() {
    // Mutex示例
    let shared_mutex = Arc::new(SharedDataMutex::new());
    let shared_mutex_clone = shared_mutex.clone();
    let mut handles = Vec::new();
    for _ in 0..10 {
        let handle = thread::spawn(move || {
            shared_mutex_clone.write(42);
            let result = shared_mutex_clone.read();
            println!("Mutex read result: {}", result);
        });
        handles.push(handle);
    }
    for handle in handles {
        handle.join().unwrap();
    }

    // RwLock示例
    let shared_rwlock = Arc::new(SharedDataRwLock::new());
    let shared_rwlock_clone = shared_rwlock.clone();
    let mut read_handles = Vec::new();
    for _ in 0..10 {
        let handle = thread::spawn(move || {
            let result = shared_rwlock_clone.read();
            println!("RwLock read result: {}", *result);
        });
        read_handles.push(handle);
    }
    let write_handle = thread::spawn(move || {
        shared_rwlock.write().unwrap().replace(42);
    });
    write_handle.join().unwrap();
    for handle in read_handles {
        handle.join().unwrap();
    }
}