MST

星途 面试题库

面试题:Rust中延迟初始化原子技巧的基础应用

请描述在Rust中,如何使用原子类型(如`AtomicBool`、`AtomicPtr`等)来实现一个简单的延迟初始化场景。假设你有一个复杂对象`ComplexObject`,需要在首次使用时进行初始化,且要保证线程安全。请写出关键代码片段并简要解释。
19.5万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

一键面试
  1. 引入必要的包
    use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
    
  2. 定义ComplexObject结构体
    struct ComplexObject {
        // 这里假设`ComplexObject`有一些字段,例如
        data: String,
    }
    
    impl ComplexObject {
        fn new() -> Self {
            ComplexObject {
                data: "Initial data".to_string(),
            }
        }
    }
    
  3. 使用AtomicBoolArc实现延迟初始化
    struct LazyComplexObject {
        initialized: AtomicBool,
        inner: Option<Arc<ComplexObject>>,
    }
    
    impl LazyComplexObject {
        fn new() -> Self {
            LazyComplexObject {
                initialized: AtomicBool::new(false),
                inner: None,
            }
        }
    
        fn get(&self) -> Arc<ComplexObject> {
            if self.initialized.load(Ordering::SeqCst) {
                self.inner.as_ref().unwrap().clone()
            } else {
                let new_obj = Arc::new(ComplexObject::new());
                if self.initialized.compare_and_swap(false, true, Ordering::SeqCst) {
                    // 如果在比较并交换时已经被其他线程初始化了,就丢弃当前创建的对象
                    drop(new_obj);
                    self.inner.as_ref().unwrap().clone()
                } else {
                    self.inner = Some(new_obj.clone());
                    new_obj
                }
            }
        }
    }
    

解释

  • LazyComplexObject结构体包含一个AtomicBool类型的initialized字段,用于标记ComplexObject是否已经初始化,以及一个Option<Arc<ComplexObject>>类型的inner字段,用于存储初始化后的ComplexObject
  • LazyComplexObject::new方法初始化initializedfalseinnerNone
  • LazyComplexObject::get方法首先检查initialized是否为true,如果是则直接返回已初始化的ComplexObject。如果initializedfalse,则创建一个新的ComplexObject。然后使用compare_and_swap方法尝试将initializedfalse设置为true。如果设置成功,表示当前线程成功初始化对象,将新创建的对象存入inner并返回。如果设置失败,说明其他线程已经完成初始化,丢弃当前创建的对象并返回已有的对象。这种方式保证了在多线程环境下ComplexObject只会被初始化一次且线程安全。