Struct std::sync::Once 1.0.0[−][src]
pub struct Once { /* fields omitted */ }
Expand description
同步原语,可用于运行一次性初始化。
对于 FFI 或相关功能的一次性初始化很有用。
该类型只能用 Once::new()
构造。
Examples
use std::sync::Once; static START: Once = Once::new(); START.call_once(|| { // 在这里运行初始化 });Run
Implementations
仅执行一次初始化例程。如果这是第一次调用 call_once
,则将执行给定的闭包,否则将 不 调用例程。
如果当前正在运行另一个初始化例程,则此方法将阻止调用线程。
当此函数返回时,可以确保某些初始化已运行并完成 (它可能不是指定的闭包)。 还可以确保此时其他线程可以可靠地观察到由执行的闭包执行的任何内存写操作 (闭包与返回之后执行的代码之间存在先于发生的关系)。
如果给定的闭包在同一 Once
实例上递归调用 call_once
,则未指定确切的行为,则允许的结果为 panic 或死锁。
Examples
use std::sync::Once; static mut VAL: usize = 0; static INIT: Once = Once::new(); // 在很多情况下,访问 `static mut` 是不安全的,但是如果我们以同步方式进行操作 (例如,一次写入或全部读取),那么我们就可以开始了! // 此函数将只调用一次 `expensive_computation`,否则将始终返回从第一次调用返回的值。 fn get_cached_val() -> usize { unsafe { INIT.call_once(|| { VAL = expensive_computation(); }); VAL } } fn expensive_computation() -> usize { // ... }Run
Panics
如果在多个线程中同时调用闭包 f
,则将仅执行一次。
但是,如果该闭包 panics 将会毒化该 Once
实例,从而导致 call_once
的所有 future 调用也变为 panic。
这类似于 poisoning with mutexes。
执行与 call_once()
相同的函数,只是忽略中毒。
与 call_once()
不同,如果此 Once
已中毒 (例如,先前对 call_once()
或 call_once_force()
的调用导致 panic),则调用 call_once_force()
仍将调用闭包 f
,并且 not 会立即导致 panic。
如果 f
panics,则 Once
将保持中毒状态。
如果 f
执行 not panic,则 Once
将不再处于中毒状态,并且所有对 call_once()
或 call_once_force()
的 future 调用都将变为无操作。
闭包 f
产生 OnceState
结构体,可用于查询 Once
的中毒状态。
Examples
use std::sync::Once; use std::thread; static INIT: Once = Once::new(); // 中毒一次 let handle = thread::spawn(|| { INIT.call_once(|| panic!()); }); assert!(handle.join().is_err()); // 中毒传播 let handle = thread::spawn(|| { INIT.call_once(|| {}); }); assert!(handle.join().is_err()); // call_once_force 仍将运行并重置中毒状态 INIT.call_once_force(|state| { assert!(state.is_poisoned()); }); // 一旦成功,我们就停止传播毒药 INIT.call_once(|| {});Run
如果某些 call_once()
调用已成功完成,则返回 true
。具体而言,在以下情况下,is_completed
将返回 false:
call_once()
根本没有被呼唤,call_once()
被称为,但尚未完成,Once
实例中毒
此函数返回 false
并不意味着 Once
尚未执行。
例如,它可能是在 is_completed
开始执行到返回之间的时间执行的,在这种情况下,false
的返回值将是陈旧的 (但仍然是允许的)。
Examples
use std::sync::Once; static INIT: Once = Once::new(); assert_eq!(INIT.is_completed(), false); INIT.call_once(|| { assert_eq!(INIT.is_completed(), false); }); assert_eq!(INIT.is_completed(), true);Run
use std::sync::Once; use std::thread; static INIT: Once = Once::new(); assert_eq!(INIT.is_completed(), false); let handle = thread::spawn(|| { INIT.call_once(|| panic!()); }); assert!(handle.join().is_err()); assert_eq!(INIT.is_completed(), false);Run