MST

星途 面试题库

面试题:Rust Mutex与死锁问题及解决方案

在使用Rust的Mutex时可能会出现死锁情况。请描述在多线程环境下,什么情况下会发生死锁,如何避免死锁的发生?同时给出一个代码示例,展示死锁场景,再给出修复后的代码。
29.5万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

死锁发生情况

  1. 循环依赖:多个线程相互持有对方所需资源的锁,形成循环等待。例如线程A持有锁L1并等待锁L2,而线程B持有锁L2并等待锁L1。
  2. 锁顺序不一致:不同线程以不同顺序获取多个锁。假设线程1先获取锁A再获取锁B,而线程2先获取锁B再获取锁A,如果两个线程同时执行,就可能导致死锁。

避免死锁方法

  1. 固定锁获取顺序:所有线程都按照相同的顺序获取锁,这样就不会形成循环依赖。
  2. 使用try_lock:尝试获取锁,如果获取失败就释放已获取的锁并进行其他操作,避免一直等待。
  3. 资源分配图算法:可以使用如银行家算法等资源分配算法来检测和避免死锁,但这种方法在实际应用中较为复杂。

死锁代码示例

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

fn main() {
    let resource_a = Arc::new(Mutex::new(0));
    let resource_b = Arc::new(Mutex::new(0));

    let resource_a_clone = resource_a.clone();
    let resource_b_clone = resource_b.clone();

    let handle1 = thread::spawn(move || {
        let _lock_a = resource_a_clone.lock().unwrap();
        thread::sleep(std::time::Duration::from_secs(1));
        let _lock_b = resource_b_clone.lock().unwrap();
    });

    let handle2 = thread::spawn(move || {
        let _lock_b = resource_b.lock().unwrap();
        thread::sleep(std::time::Duration::from_secs(1));
        let _lock_a = resource_a.lock().unwrap();
    });

    handle1.join().unwrap();
    handle2.join().unwrap();
}

修复后代码(固定锁获取顺序)

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

fn main() {
    let resource_a = Arc::new(Mutex::new(0));
    let resource_b = Arc::new(Mutex::new(0));

    let resource_a_clone = resource_a.clone();
    let resource_b_clone = resource_b.clone();

    let handle1 = thread::spawn(move || {
        let _lock_a = resource_a_clone.lock().unwrap();
        thread::sleep(std::time::Duration::from_secs(1));
        let _lock_b = resource_b_clone.lock().unwrap();
    });

    let handle2 = thread::spawn(move || {
        let _lock_a = resource_a.lock().unwrap();
        thread::sleep(std::time::Duration::from_secs(1));
        let _lock_b = resource_b.lock().unwrap();
    });

    handle1.join().unwrap();
    handle2.join().unwrap();
}