MST

星途 面试题库

面试题:Rust并发环境下如何确保获取修改操作的原子性与一致性

假设你正在编写一个多线程的Rust程序,其中涉及多个线程对共享资源的获取和修改操作,详细阐述如何通过Rust的特性和工具来确保这些操作的原子性与一致性,举例说明你可能会使用到的类型和方法。
27.6万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

在Rust中,处理多线程环境下共享资源的原子性与一致性,可以使用以下几种方式:

1. std::sync::Mutex(互斥锁)

  • 原理:Mutex 提供了一种机制,通过锁定资源,同一时间只允许一个线程访问共享资源,从而保证原子性和一致性。
  • 示例
use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let data = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let data = Arc::clone(&data);
        let handle = thread::spawn(move || {
            let mut num = data.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }

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

    println!("Final value: {}", *data.lock().unwrap());
}

2. std::sync::RwLock(读写锁)

  • 原理:RwLock 允许多个线程同时进行读操作,但只允许一个线程进行写操作。当有写操作时,所有读操作和其他写操作都会被阻塞,保证数据一致性。
  • 示例
use std::sync::{Arc, RwLock};
use std::thread;

fn main() {
    let data = Arc::new(RwLock::new(String::from("initial value")));

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

    let write_handle = thread::spawn(move || {
        let mut write_data = data.write().unwrap();
        *write_data = String::from("new value");
    });

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

3. 原子类型(std::sync::atomic

  • 原理std::sync::atomic 模块提供了原子类型,如 AtomicI32AtomicU64 等,这些类型的操作是原子的,不需要额外的锁机制就可以在多线程环境下安全使用。
  • 示例
use std::sync::atomic::{AtomicI32, Ordering};
use std::thread;

fn main() {
    let data = AtomicI32::new(0);
    let mut handles = vec![];

    for _ in 0..10 {
        let data = &data;
        let handle = thread::spawn(move || {
            data.fetch_add(1, Ordering::SeqCst);
        });
        handles.push(handle);
    }

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

    println!("Final value: {}", data.load(Ordering::SeqCst));
}

通过这些类型和方法,Rust 提供了强大的工具来确保多线程程序中共享资源操作的原子性与一致性。具体选择哪种方式取决于实际需求,如读多写少的场景适合 RwLock,简单的数值操作适合原子类型,而复杂的数据结构则可能需要 Mutex 来保护。