面试题答案
一键面试使用原子操作实现延迟初始化的基本步骤
- 定义原子变量:使用
std::sync::atomic
模块中的原子类型,如AtomicBool
、AtomicPtr
等,来标记初始化状态。 - 初始化逻辑:编写实际的初始化逻辑,该逻辑可能会涉及到一些复杂的计算或者资源分配。
- 原子操作:使用原子操作(如
compare_and_swap
)来确保初始化只发生一次,避免竞争条件。
示例:使用std::sync::Once
和原子类型完成延迟初始化全局变量
use std::sync::{Once, AtomicPtr};
use std::mem;
// 定义一个全局原子指针
static mut GLOBAL_VARIABLE: *const i32 = 0 as *const i32;
static INIT: Once = Once::new();
fn get_global_variable() -> &'static i32 {
INIT.call_once(|| {
let value = 42;
let boxed = Box::new(value);
unsafe {
GLOBAL_VARIABLE = Box::into_raw(boxed);
}
});
unsafe {
&*GLOBAL_VARIABLE
}
}
在这个例子中:
GLOBAL_VARIABLE
是一个全局的原子指针,初始化为空指针。INIT
是一个Once
类型的静态变量,用于确保初始化只执行一次。get_global_variable
函数在第一次调用时,会通过INIT.call_once
执行初始化逻辑,创建一个值为42
的i32
,并将其地址存储在GLOBAL_VARIABLE
中。后续调用get_global_variable
时,直接返回已初始化的值。
另外,更简洁地使用OnceCell
(从Rust 1.52.0开始可用)实现延迟初始化全局变量:
use std::sync::OnceCell;
static GLOBAL_VARIABLE: OnceCell<i32> = OnceCell::new();
fn get_global_variable() -> &'static i32 {
GLOBAL_VARIABLE.get_or_init(|| {
42
})
}
这里OnceCell
内部封装了原子操作,get_or_init
方法会在变量未初始化时执行初始化闭包,确保初始化只发生一次,并且代码更加简洁。