面试题答案
一键面试多个线程共享资源面临的问题
- 竞态条件(Race Condition):多个线程同时访问和修改共享资源,导致最终结果依赖于线程执行的顺序,产生不可预测的行为。例如,多个线程同时对一个共享的计数器进行递增操作,可能会出现计数不准确的情况。
- 数据不一致:由于线程执行的异步性,一个线程对共享资源的修改可能不会及时被其他线程看到,导致数据在不同线程间呈现不一致的状态。
使用Rust机制解决问题
- Mutex(互斥锁)
- 原理:Mutex 是一种同步原语,它通过锁定资源,确保在任何时刻只有一个线程可以访问共享资源。当一个线程获取了 Mutex 的锁,其他线程必须等待锁被释放才能访问资源。
- 示例:
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Final counter value: {}", *counter.lock().unwrap());
}
在这个例子中,Arc<Mutex<i32>>
用于在多个线程间共享一个计数器。每个线程通过 counter.lock().unwrap()
获取锁来访问和修改计数器,确保了同一时间只有一个线程能操作计数器,避免了竞态条件。
2. Arc(原子引用计数)
- 原理:Arc
用于在多个线程间共享数据,它通过原子引用计数机制来管理数据的生命周期。Arc
允许在多个线程间克隆,每个克隆都指向相同的数据,并且当所有指向数据的 Arc
实例都被销毁时,数据才会被释放。通常与 Mutex
结合使用,Arc
用于共享数据,Mutex
用于保护数据的访问。
- 示例:上述代码中就使用了 Arc
来在多个线程间共享 Mutex
包裹的计数器。Arc::clone(&counter)
克隆了 Arc
实例,使得每个线程都可以持有对共享计数器的引用,同时通过 Mutex
保证了对计数器访问的安全性。