死锁发生情况
- 循环依赖:多个线程相互持有对方所需资源的锁,形成循环等待。例如线程A持有锁L1并等待锁L2,而线程B持有锁L2并等待锁L1。
- 锁顺序不一致:不同线程以不同顺序获取多个锁。假设线程1先获取锁A再获取锁B,而线程2先获取锁B再获取锁A,如果两个线程同时执行,就可能导致死锁。
避免死锁方法
- 固定锁获取顺序:所有线程都按照相同的顺序获取锁,这样就不会形成循环依赖。
- 使用
try_lock
:尝试获取锁,如果获取失败就释放已获取的锁并进行其他操作,避免一直等待。
- 资源分配图算法:可以使用如银行家算法等资源分配算法来检测和避免死锁,但这种方法在实际应用中较为复杂。
死锁代码示例
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();
}