面试题答案
一键面试可能导致死锁的场景
- 循环依赖:线程A持有锁1,试图获取锁2;线程B持有锁2,试图获取锁1。这就形成了循环依赖,导致死锁。例如:
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let lock1 = Arc::new(Mutex::new(0));
let lock2 = Arc::new(Mutex::new(0));
let lock1_clone = lock1.clone();
let lock2_clone = lock2.clone();
let thread1 = thread::spawn(move || {
let _guard1 = lock1_clone.lock().unwrap();
thread::sleep(std::time::Duration::from_secs(1));
let _guard2 = lock2_clone.lock().unwrap();
});
let thread2 = thread::spawn(move || {
let _guard2 = lock2.lock().unwrap();
thread::sleep(std::time::Duration::from_secs(1));
let _guard1 = lock1.lock().unwrap();
});
thread1.join().unwrap();
thread2.join().unwrap();
}
- 嵌套锁获取顺序不一致:不同线程以不同顺序获取多个锁,可能导致死锁。
避免死锁的策略
- 固定锁获取顺序:所有线程都按照相同的顺序获取锁。例如,总是先获取
lock1
,再获取lock2
。
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let lock1 = Arc::new(Mutex::new(0));
let lock2 = Arc::new(Mutex::new(0));
let lock1_clone = lock1.clone();
let lock2_clone = lock2.clone();
let thread1 = thread::spawn(move || {
let _guard1 = lock1_clone.lock().unwrap();
let _guard2 = lock2_clone.lock().unwrap();
});
let thread2 = thread::spawn(move || {
let _guard1 = lock1.lock().unwrap();
let _guard2 = lock2.lock().unwrap();
});
thread1.join().unwrap();
thread2.join().unwrap();
}
- 使用超时机制:在获取锁时设置超时时间,如果在超时时间内没有获取到锁,则放弃操作,避免无限等待。
使用try_lock
方法检测和避免死锁
try_lock
方法尝试获取锁,如果锁可用则返回一个Result
包含锁的Guard
,如果锁不可用则立即返回Err
。
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let lock1 = Arc::new(Mutex::new(0));
let lock2 = Arc::new(Mutex::new(0));
let lock1_clone = lock1.clone();
let lock2_clone = lock2.clone();
let thread1 = thread::spawn(move || {
if let Ok(_guard1) = lock1_clone.try_lock() {
if let Ok(_guard2) = lock2_clone.try_lock() {
// 成功获取两个锁,可以进行操作
} else {
// 未能获取锁2,释放锁1
drop(_guard1);
}
}
});
let thread2 = thread::spawn(move || {
if let Ok(_guard2) = lock2.lock() {
if let Ok(_guard1) = lock1.try_lock() {
// 成功获取两个锁,可以进行操作
} else {
// 未能获取锁1,释放锁2
drop(_guard2);
}
}
});
thread1.join().unwrap();
thread2.join().unwrap();
}
通过try_lock
方法,线程可以尝试获取锁并根据结果决定是否继续等待或放弃,从而避免死锁。