面试题答案
一键面试1. 使用 Arc
和 Mutex
管理共享资源
Arc
(原子引用计数)用于在多线程环境下共享数据,Mutex
(互斥锁)用于保护共享数据,防止竞态条件。
use std::sync::{Arc, Mutex};
fn main() {
let shared_data = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let data = shared_data.clone();
let handle = std::thread::spawn(move || {
let mut num = data.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
let result = shared_data.lock().unwrap();
println!("Final value: {}", *result);
}
2. 错误处理
在 lock
操作时,unwrap
方法会在锁获取失败(如死锁)时直接导致程序崩溃。更好的做法是使用 try_lock
或者 lock
结合 Result
处理错误。
use std::sync::{Arc, Mutex};
fn main() {
let shared_data = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let data = shared_data.clone();
let handle = std::thread::spawn(move || {
match data.try_lock() {
Ok(mut num) => {
*num += 1;
}
Err(e) => {
eprintln!("Error locking mutex: {:?}", e);
}
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
match shared_data.try_lock() {
Ok(result) => {
println!("Final value: {}", *result);
}
Err(e) => {
eprintln!("Error locking mutex: {:?}", e);
}
}
}
3. 减少锁争用
- 细粒度锁:将大的共享资源拆分成多个小的部分,每个部分使用独立的锁。
- 读写锁:如果共享资源读多写少,可以使用
RwLock
。读操作可以并发执行,写操作需要独占锁。
use std::sync::{Arc, RwLock};
fn main() {
let shared_data = Arc::new(RwLock::new(String::new()));
let mut handles = vec![];
for _ in 0..5 {
let data = shared_data.clone();
let handle = std::thread::spawn(move || {
let read_data = data.read().unwrap();
println!("Read data: {}", read_data);
});
handles.push(handle);
}
let write_handle = std::thread::spawn(move || {
let mut write_data = shared_data.write().unwrap();
*write_data = "Hello, world!".to_string();
});
for handle in handles {
handle.join().unwrap();
}
write_handle.join().unwrap();
}
4. 错误恢复机制
- 线程隔离:每个线程独立运行,当某个线程出现错误时,不会影响其他线程。可以通过
thread::spawn
的错误处理来实现。 - 监控与重启:使用
std::sync::mpsc
通道来监控线程状态,当线程出现错误时,重新启动该线程。
use std::sync::mpsc;
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
let handle = thread::spawn(move || {
if let Err(e) = some_function_that_might_fail() {
tx.send(e).unwrap();
}
});
let result = handle.join();
if let Err(_) = result {
eprintln!("Thread panicked");
}
if let Ok(error) = rx.recv() {
eprintln!("Error in thread: {:?}", error);
// 这里可以实现重启线程的逻辑
}
}
fn some_function_that_might_fail() -> Result<(), String> {
// 模拟可能失败的操作
Err("Some error".to_string())
}
通过以上方法,可以设计出一种健壮的错误处理与恢复机制,在高并发 Rust 应用中有效管理共享资源,提高系统的容错能力和稳定性。