面试题答案
一键面试死锁产生原因
死锁通常在多个线程相互等待对方释放资源时发生。具体来说,当线程A持有资源1并等待资源2,而线程B持有资源2并等待资源1时,死锁就会出现。在Rust线程中使用同步函数调用时,如果线程获取锁的顺序不一致,或者在持有锁的情况下进行阻塞操作,都可能导致死锁。例如,两个线程都试图获取两个不同的Mutex
,但获取顺序相反,就可能产生死锁。
预防死锁的方法
- 固定锁获取顺序:确保所有线程以相同的顺序获取锁。例如:
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let mutex1 = Arc::new(Mutex::new(0));
let mutex2 = Arc::new(Mutex::new(1));
let mutex1_clone = mutex1.clone();
let mutex2_clone = mutex2.clone();
let handle1 = thread::spawn(move || {
let mut lock1 = mutex1_clone.lock().unwrap();
let mut lock2 = mutex2_clone.lock().unwrap();
// 使用锁保护的资源
*lock1 += *lock2;
});
let handle2 = thread::spawn(move || {
let mut lock1 = mutex1.lock().unwrap();
let mut lock2 = mutex2.lock().unwrap();
// 使用锁保护的资源
*lock2 -= *lock1;
});
handle1.join().unwrap();
handle2.join().unwrap();
}
在这个例子中,两个线程都先获取mutex1
,再获取mutex2
,避免了死锁。
- 使用
try_lock
方法:Mutex
提供了try_lock
方法,该方法尝试获取锁,如果锁不可用,不会阻塞线程,而是返回Err
。可以利用这个方法来避免死锁。例如:
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let mutex1 = Arc::new(Mutex::new(0));
let mutex2 = Arc::new(Mutex::new(1));
let mutex1_clone = mutex1.clone();
let mutex2_clone = mutex2.clone();
let handle1 = thread::spawn(move || {
match (mutex1_clone.try_lock(), mutex2_clone.try_lock()) {
(Ok(mut lock1), Ok(mut lock2)) => {
// 使用锁保护的资源
*lock1 += *lock2;
}
_ => {
// 无法获取锁,处理错误
println!("无法获取锁");
}
}
});
let handle2 = thread::spawn(move || {
match (mutex1.try_lock(), mutex2.try_lock()) {
(Ok(mut lock1), Ok(mut lock2)) => {
// 使用锁保护的资源
*lock2 -= *lock1;
}
_ => {
// 无法获取锁,处理错误
println!("无法获取锁");
}
}
});
handle1.join().unwrap();
handle2.join().unwrap();
}
在这个例子中,通过try_lock
尝试获取锁,如果无法获取,则进行相应的错误处理,避免了死锁。