MST

星途 面试题库

面试题:Rust并发中如何处理共享可变状态及数据竞争

假设你有一个共享的可变数据结构(比如`Vec<i32>`),需要多个线程同时对其进行读写操作。在Rust中,怎样使用`Mutex`、`RwLock`等机制来确保数据的一致性,避免数据竞争?请给出具体的代码示例,并解释每种机制适用的场景。
39.2万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

使用Mutex

Mutex(互斥锁)用于保证同一时间只有一个线程可以访问数据,适用于读写操作都可能修改数据的场景。

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

fn main() {
    let shared_data = Arc::new(Mutex::new(Vec::from([1, 2, 3])));

    let mut handles = vec![];
    for _ in 0..3 {
        let data = Arc::clone(&shared_data);
        let handle = thread::spawn(move || {
            let mut data = data.lock().unwrap();
            data.push(4);
            println!("Thread modified data: {:?}", data);
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    let final_data = shared_data.lock().unwrap();
    println!("Final data: {:?}", final_data);
}

在上述代码中,Mutex包裹了Vec<i32>lock方法获取锁,返回一个MutexGuard,它实现了DerefDerefMut,因此可以像使用原始的Vec<i32>一样操作数据。

使用RwLock

RwLock(读写锁)允许多个线程同时进行读操作,但只允许一个线程进行写操作。适用于读操作远远多于写操作的场景,因为读操作不互斥,能提高并发性能。

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

fn main() {
    let shared_data = Arc::new(RwLock::new(Vec::from([1, 2, 3])));

    let mut read_handles = vec![];
    for _ in 0..3 {
        let data = Arc::clone(&shared_data);
        let handle = thread::spawn(move || {
            let data = data.read().unwrap();
            println!("Thread read data: {:?}", data);
        });
        read_handles.push(handle);
    }

    let write_handle = thread::spawn(move || {
        let mut data = shared_data.write().unwrap();
        data.push(4);
        println!("Thread modified data: {:?}", data);
    });

    for handle in read_handles {
        handle.join().unwrap();
    }
    write_handle.join().unwrap();

    let final_data = shared_data.read().unwrap();
    println!("Final data: {:?}", final_data);
}

这里RwLock包裹了Vec<i32>。读操作使用read方法获取一个只读的锁(返回RwLockReadGuard),写操作使用write方法获取一个可写的锁(返回RwLockWriteGuard)。

场景总结

  • Mutex:适用于读写操作都会修改数据的场景,确保同一时间只有一个线程能访问数据,避免数据竞争。
  • RwLock:适用于读多写少的场景,读操作可并发执行,写操作独占,提高整体并发性能。