MST

星途 面试题库

面试题:Rust 中线程与异步编程结合时如何处理共享状态

在 Rust 中,当使用线程和异步编程结合时,共享状态的处理是一个重要问题。假设你有一个共享的计数器,需要在线程和异步任务中进行安全的读写操作,请描述你会使用哪些机制(如 Mutex、Arc 等)来确保共享状态的一致性和线程安全,并给出简单的代码示例。
24.5万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试
  1. 使用的机制

    • Arc(原子引用计数):用于在多个线程间共享数据。Arc 允许在堆上分配的数据有多个所有者,同时提供原子引用计数,使得在多线程环境下安全地共享数据成为可能。
    • Mutex(互斥锁):用于保护共享数据,确保同一时间只有一个线程可以访问数据。当一个线程获取了 Mutex 的锁,其他线程必须等待锁被释放才能访问被保护的数据。
    • async_std::sync::Arcasync_std::sync::Mutex:在异步编程场景下,async_std 库提供了异步版本的 ArcMutex,用于在异步任务间安全地共享状态。
  2. 代码示例

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

// 普通线程场景
fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

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

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

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

// 异步场景
use async_std::prelude::*;
use async_std::sync::{Arc, Mutex};
use async_std::task;

#[async_std::main]
async fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut tasks = vec![];

    for _ in 0..10 {
        let counter = Arc::clone(&counter);
        let task = task::spawn(async move {
            let mut num = counter.lock().await;
            *num += 1;
        });
        tasks.push(task);
    }

    for task in tasks {
        task.await.unwrap();
    }

    println!("Final counter value: {}", *counter.lock().await);
}

在上述代码中:

  • 普通线程场景使用了 std::sync::Arcstd::sync::Mutex,通过 thread::spawn 创建线程,在线程中获取 Mutex 的锁来修改共享的计数器。
  • 异步场景使用了 async_std::sync::Arcasync_std::sync::Mutex,通过 async_std::task::spawn 创建异步任务,在异步任务中通过 await 获取 Mutex 的锁来修改共享的计数器。