MST

星途 面试题库

面试题:Rust同步通道在并发场景下如何避免死锁

在Rust中使用同步通道构建并发程序时,可能会出现死锁情况。请阐述可能导致死锁的常见场景,并给出至少一种避免死锁的具体方法,同时用代码示例说明。
22.9万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试

常见导致死锁的场景

  1. 循环依赖:多个线程互相等待对方持有的资源,形成一个环形依赖。例如线程A持有资源R1并等待资源R2,而线程B持有资源R2并等待资源R1。
  2. 锁顺序不一致:不同线程以不同顺序获取锁。假设线程1先获取锁A再获取锁B,而线程2先获取锁B再获取锁A,如果线程1获取锁A后,线程2获取锁B,此时双方再尝试获取对方已持有的锁就会导致死锁。

避免死锁的方法

  1. 使用资源分配图算法(如银行家算法):该算法可以在资源分配前检查是否会导致死锁,但实现较为复杂,在Rust中不常用。
  2. 按固定顺序获取锁:确保所有线程都以相同的顺序获取锁。在同步通道场景下,可以理解为按固定顺序操作通道。

代码示例

use std::sync::mpsc::{channel, Receiver, Sender};
use std::thread;

fn main() {
    let (tx1, rx1): (Sender<i32>, Receiver<i32>) = channel();
    let (tx2, rx2): (Sender<i32>, Receiver<i32>) = channel();

    let handle1 = thread::spawn(move || {
        // 按固定顺序发送数据
        tx1.send(1).unwrap();
        let data = rx2.recv().unwrap();
        println!("Thread 1 received: {}", data);
    });

    let handle2 = thread::spawn(move || {
        // 按固定顺序发送数据
        tx2.send(2).unwrap();
        let data = rx1.recv().unwrap();
        println!("Thread 2 received: {}", data);
    });

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

在上述代码中,两个线程按相同顺序操作通道,避免了死锁。如果不按此固定顺序,例如线程1先从rx2接收再向tx1发送,线程2先从rx1接收再向tx2发送,就可能会导致死锁。