Struct Once
struct Once { ... }
A low-level synchronization primitive for one-time global execution.
Previously this was the only "execute once" synchronization in std.
Other libraries implemented novel synchronizing types with Once, like
OnceLock<T> or LazyLock<T, F>, before those were added to std.
OnceLock<T> in particular supersedes Once in functionality and should
be preferred for the common case where the Once is associated with data.
This type can only be constructed with [Once::new()].
Examples
use Once;
static START: Once = new;
START.call_once;
Implementations
impl Once
const fn new() -> OnceCreates a new
Oncevalue.fn call_once<F>(self: &Self, f: F) where F: FnOnce()Performs an initialization routine once and only once. The given closure will be executed if this is the first time
call_oncehas been called, and otherwise the routine will not be invoked.This method will block the calling thread if another initialization routine is currently running.
When this function returns, it is guaranteed that some initialization has run and completed (it might not be the closure specified). It is also guaranteed that any memory writes performed by the executed closure can be reliably observed by other threads at this point (there is a happens-before relation between the closure and code executing after the return).
If the given closure recursively invokes
call_onceon the sameOnceinstance, the exact behavior is not specified: allowed outcomes are a panic or a deadlock.Examples
use Once; static mut VAL: usize = 0; static INIT: Once = new; // Accessing a `static mut` is unsafe much of the time, but if we do so // in a synchronized fashion (e.g., write once or read all) then we're // good to go! // // This function will only call `expensive_computation` once, and will // otherwise always return the value returned from the first invocation.Panics
The closure
fwill only be executed once even if this is called concurrently amongst many threads. If that closure panics, however, then it will poison thisOnceinstance, causing all future invocations ofcall_onceto also panic.This is similar to poisoning with mutexes, but this mechanism is guaranteed to never skip panics within
f.fn call_once_force<F>(self: &Self, f: F) where F: FnOnce(&OnceState)Performs the same function as
call_once()except ignores poisoning.Unlike
call_once(), if thisOncehas been poisoned (i.e., a previous call tocall_once()orcall_once_force()caused a panic), callingcall_once_force()will still invoke the closurefand will not result in an immediate panic. Iffpanics, theOncewill remain in a poison state. Iffdoes not panic, theOncewill no longer be in a poison state and all future calls tocall_once()orcall_once_force()will be no-ops.The closure
fis yielded aOnceStatestructure which can be used to query the poison status of theOnce.Examples
use Once; use thread; static INIT: Once = new; // poison the once let handle = spawn; assert!; // poisoning propagates let handle = spawn; assert!; // call_once_force will still run and reset the poisoned state INIT.call_once_force; // once any success happens, we stop propagating the poison INIT.call_once;fn is_completed(self: &Self) -> boolReturns
trueif somecall_once()call has completed successfully. Specifically,is_completedwill return false in the following situations:call_once()was not called at all,call_once()was called, but has not yet completed,- the
Onceinstance is poisoned
This function returning
falsedoes not mean thatOncehas not been executed. For example, it may have been executed in the time between whenis_completedstarts executing and when it returns, in which case thefalsereturn value would be stale (but still permissible).Examples
use Once; static INIT: Once = new; assert_eq!; INIT.call_once; assert_eq!;use Once; use thread; static INIT: Once = new; assert_eq!; let handle = spawn; assert!; assert_eq!;fn wait(self: &Self)Blocks the current thread until initialization has completed.
Example
use Once; use thread; static READY: Once = new; let thread = spawn; READY.call_once;Panics
If this
Oncehas been poisoned because an initialization closure has panicked, this method will also panic. Usewait_forceif this behavior is not desired.fn wait_force(self: &Self)Blocks the current thread until initialization has completed, ignoring poisoning.
If this
Oncehas been poisoned, this function blocks until it becomes completed, unlike [Once::wait()], which panics in this case.
impl Debug for Once
fn fmt(self: &Self, f: &mut Formatter<'_>) -> Result
impl Freeze for Once
impl RefUnwindSafe for Once
impl Send for Once
impl Sync for Once
impl Unpin for Once
impl UnsafeUnpin for Once
impl UnwindSafe for Once
impl<T> Any for Once
fn type_id(self: &Self) -> TypeId
impl<T> Borrow for Once
fn borrow(self: &Self) -> &T
impl<T> BorrowMut for Once
fn borrow_mut(self: &mut Self) -> &mut T
impl<T> From for Once
fn from(t: T) -> TReturns the argument unchanged.
impl<T, U> Into for Once
fn into(self: Self) -> UCalls
U::from(self).That is, this conversion is whatever the implementation of
[From]<T> for Uchooses to do.
impl<T, U> TryFrom for Once
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
impl<T, U> TryInto for Once
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error>