MST

星途 面试题库

面试题:Rust线程间数据共享与同步

假设你有一个共享的可变数据结构,在多个Rust线程间访问,可能会出现数据竞争问题。请描述使用`Mutex`结合`Thread`类型来安全共享数据的步骤,并给出代码示例。同时说明`Mutex`的工作原理以及`lock`方法的作用。
46.6万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

使用Mutex结合Thread类型安全共享数据的步骤

  1. 引入必要的模块:在Rust中,需要引入std::sync::{Mutex, Thread}模块,用于处理线程和互斥锁。
  2. 创建共享数据和Mutex:定义一个共享的数据结构,并使用Mutex将其包裹起来,这样可以保证在同一时间只有一个线程能够访问该数据。
  3. 创建线程:使用Thread::spawn创建多个线程,每个线程在访问共享数据之前,需要先获取Mutex的锁。
  4. 获取锁并访问数据:在线程内部,使用lock方法获取Mutex的锁。如果锁可用,该方法会返回一个LockResult,通过unwrap方法可以获取到锁对象,进而访问共享数据。如果锁不可用,线程会被阻塞,直到锁被释放。
  5. 释放锁:当线程完成对共享数据的访问后,Mutex的锁会自动释放(通过Drop trait),其他线程就有机会获取锁并访问数据。

代码示例

use std::sync::{Mutex, Thread};

fn main() {
    // 创建共享数据和Mutex
    let shared_data = Mutex::new(0);

    let handles: Vec<_> = (0..10).map(|_| {
        let data = shared_data.clone();
        Thread::spawn(move || {
            // 获取锁并访问数据
            let mut num = data.lock().unwrap();
            *num += 1;
            println!("Thread incremented data to: {}", *num);
        })
    }).collect();

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

    let final_value = shared_data.lock().unwrap();
    println!("Final value of shared data: {}", *final_value);
}

Mutex的工作原理

Mutex(互斥锁)是一种同步原语,它通过内部的一个标志位来表示锁的状态。当一个线程尝试获取锁时,Mutex会检查这个标志位。如果标志位表示锁是空闲的,Mutex会将标志位设置为锁定状态,并允许线程继续执行。如果标志位表示锁已经被占用,线程会被阻塞,放入一个等待队列中。当持有锁的线程释放锁时,Mutex会将标志位设置为空闲状态,并从等待队列中唤醒一个线程,让它获取锁。

lock方法的作用

lock方法用于尝试获取Mutex的锁。如果锁当前可用,lock方法会返回一个LockResult,其中包含一个代表锁的智能指针(MutexGuard)。这个智能指针实现了DerefDerefMut trait,因此可以像操作原始数据一样操作共享数据。当MutexGuard离开作用域时,其Drop实现会自动释放锁。如果锁当前不可用,lock方法会阻塞当前线程,直到锁被释放。