面试题答案
一键面试设计思路
- 选择同步原语:
- 对于多线程间共享数据的访问控制,
Mutex
(互斥锁)是一个常用的同步原语。它能保证同一时间只有一个线程可以访问被保护的数据。在Rust中,std::sync::Mutex
提供了这样的功能。 - 对于需要在多个线程间传递数据并保证线程安全,
Arc
(原子引用计数)可以和Mutex
结合使用。Arc
允许在多个线程间共享数据,并且其内部的引用计数操作是原子的,确保了在多线程环境下的安全。
- 对于多线程间共享数据的访问控制,
- 处理竞争条件:
- 通过在访问共享的元组结构体数据前获取
Mutex
的锁,来防止多个线程同时访问和修改数据,从而避免竞争条件。当一个线程获取到锁后,其他线程必须等待锁被释放才能访问数据。
- 通过在访问共享的元组结构体数据前获取
- 处理死锁问题:
- 为了避免死锁,要确保线程获取锁的顺序一致。例如,如果有多个
Mutex
,所有线程都按照相同的顺序获取这些锁。另外,尽量减少锁的持有时间,尽快处理完需要保护的数据并释放锁。
- 为了避免死锁,要确保线程获取锁的顺序一致。例如,如果有多个
核心代码示例(以Rust为例)
use std::sync::{Arc, Mutex};
use std::thread;
// 定义元组结构体
type IntermediateResult = (i32, f64);
fn main() {
// 使用Arc和Mutex来包装元组结构体,使其线程安全
let shared_result = Arc::new(Mutex::new((0, 0.0)));
let mut handles = vec![];
for _ in 0..10 {
let result_clone = shared_result.clone();
let handle = thread::spawn(move || {
// 获取锁
let mut result = result_clone.lock().unwrap();
// 模拟中间计算结果更新
result.0 += 1;
result.1 += 1.5;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
// 最后查看结果
let final_result = shared_result.lock().unwrap();
println!("Final result: ({}, {})", final_result.0, final_result.1);
}
在上述代码中:
- 定义了
IntermediateResult
类型别名,表示元组结构体。 - 使用
Arc<Mutex<IntermediateResult>>
来包装元组结构体,使其可以在线程间安全共享。 - 在每个线程中,通过
lock
方法获取Mutex
的锁,对元组结构体进行操作,操作完成后锁会自动释放(由于MutexGuard
的自动析构)。 - 主线程等待所有子线程完成后,获取最终的计算结果并打印。