面试题答案
一键面试引入死锁的代码
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 thread1 = thread::spawn(move || {
let _lock_a = resource_a_clone.lock().unwrap();
thread::sleep(std::time::Duration::from_millis(100));
let _lock_b = resource_b_clone.lock().unwrap();
println!("Thread 1 acquired both locks");
});
let thread2 = thread::spawn(move || {
let _lock_b = resource_b.lock().unwrap();
thread::sleep(std::time::Duration::from_millis(100));
let _lock_a = resource_a.lock().unwrap();
println!("Thread 2 acquired both locks");
});
thread1.join().unwrap();
thread2.join().unwrap();
}
死锁产生原因分析
死锁产生是因为thread1
首先获取resource_a
的锁,然后尝试获取resource_b
的锁;而thread2
首先获取resource_b
的锁,然后尝试获取resource_a
的锁。当thread1
获取了resource_a
的锁,thread2
获取了resource_b
的锁时,它们相互等待对方释放锁,从而陷入死锁。
避免死锁的方法及修改后代码
方法一:按照固定顺序获取锁
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 thread1 = thread::spawn(move || {
let _lock_a = resource_a_clone.lock().unwrap();
let _lock_b = resource_b_clone.lock().unwrap();
println!("Thread 1 acquired both locks");
});
let thread2 = thread::spawn(move || {
let _lock_a = resource_a.lock().unwrap();
let _lock_b = resource_b.lock().unwrap();
println!("Thread 2 acquired both locks");
});
thread1.join().unwrap();
thread2.join().unwrap();
}
在这个修改后的代码中,thread1
和thread2
都按照先获取resource_a
的锁,再获取resource_b
的锁的顺序进行操作,避免了循环依赖,从而避免了死锁。
方法二:使用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 thread1 = thread::spawn(move || {
let lock_a = resource_a_clone.try_lock();
if let Ok(mut _lock_a) = lock_a {
let lock_b = resource_b_clone.try_lock();
if let Ok(mut _lock_b) = lock_b {
println!("Thread 1 acquired both locks");
} else {
println!("Thread 1 could not acquire lock B, releasing lock A");
}
}
});
let thread2 = thread::spawn(move || {
let lock_b = resource_b.try_lock();
if let Ok(mut _lock_b) = lock_b {
let lock_a = resource_a.try_lock();
if let Ok(mut _lock_a) = lock_a {
println!("Thread 2 acquired both locks");
} else {
println!("Thread 2 could not acquire lock A, releasing lock B");
}
}
});
thread1.join().unwrap();
thread2.join().unwrap();
}
在这个代码中,使用try_lock
尝试获取锁,如果获取失败,就释放已经获取的锁,避免了死锁。