面试题答案
一键面试1. Once
类型保证初始化线程安全性的原理
Once
类型通过内部的状态标志和同步机制来保证初始化的线程安全性。它使用了底层的原子操作来确保只有一个线程能够执行初始化操作,其他线程在初始化完成后直接获取结果,而不会重复执行初始化代码。
2. 代码示例
以下是使用Once
与Arc
、Mutex
结合对共享资源进行线程安全初始化的Rust代码示例:
use std::sync::{Arc, Once, Mutex};
static INIT: Once = Once::new();
static mut SHARED_RESOURCE: Option<Arc<Mutex<i32>>> = None;
fn get_shared_resource() -> Arc<Mutex<i32>> {
INIT.call_once(|| {
let resource = Arc::new(Mutex::new(42));
unsafe {
SHARED_RESOURCE = Some(resource.clone());
}
});
unsafe {
SHARED_RESOURCE.as_ref().unwrap().clone()
}
}
fn main() {
let handle1 = std::thread::spawn(|| {
let resource = get_shared_resource();
let mut data = resource.lock().unwrap();
*data += 1;
println!("Thread 1: {}", *data);
});
let handle2 = std::thread::spawn(|| {
let resource = get_shared_resource();
let mut data = resource.lock().unwrap();
*data += 2;
println!("Thread 2: {}", *data);
});
handle1.join().unwrap();
handle2.join().unwrap();
}
3. 可能遇到的竞争条件及避免方法
- 竞争条件:如果没有
Once
类型,多个线程可能同时尝试初始化共享资源,导致数据竞争和不一致。例如,两个线程同时创建Arc<Mutex<i32>>
实例,使得共享资源状态混乱。 - 避免方法:通过使用
Once
类型,利用其内部的同步机制(原子操作和状态标志),保证初始化操作只执行一次。只有第一个到达call_once
的线程会执行初始化代码,其他线程等待初始化完成并直接获取结果,从而避免了竞争条件。同时,Arc
和Mutex
确保了共享资源在多线程间的安全访问,Arc
用于共享所有权,Mutex
用于互斥访问。