pub struct Once(/* private fields */);Expand description
A synchronization primitive which can be used to run a one-time initialization. Useful for one-time initialization for globals, FFI or related functionality.
When the initialization produces a value, std::sync::OnceLock is often
more convenient.
§Examples
use parking_lot::Once;
static START: Once = Once::new();
START.call_once(|| {
// run initialization here
});Implementations§
Source§impl Once
impl Once
Sourcepub const fn new_completed() -> Once
pub const fn new_completed() -> Once
Creates a new Once value that is already in the completed state.
A Once created this way will never invoke a closure passed to
call_once or call_once_force,
and its state will always be OnceState::Done.
§Examples
use parking_lot::{Once, OnceState};
static INIT: Once = Once::new_completed();
assert_eq!(INIT.state(), OnceState::Done);
// The closure is never executed.
INIT.call_once(|| unreachable!());Sourcepub fn state(&self) -> OnceState
pub fn state(&self) -> OnceState
Returns a snapshot of the current state of this Once.
The state may change immediately after this function returns.
Sourcepub fn is_completed(&self) -> bool
pub fn is_completed(&self) -> bool
Returns true if this Once is in the completed state.
A Once becomes completed when an initialization closure finishes
successfully, or when it is created with
new_completed. This method returns false if
initialization has not started, is still in progress, or the Once is
poisoned.
A false result may be stale. For example, initialization may complete
between the state being read and this function returning.
§Examples
use parking_lot::Once;
static INIT: Once = Once::new();
assert!(!INIT.is_completed());
INIT.call_once(|| {
assert!(!INIT.is_completed());
});
assert!(INIT.is_completed());
assert!(Once::new_completed().is_completed());A poisoned Once has not completed successfully:
use parking_lot::Once;
use std::thread;
static INIT: Once = Once::new();
let handle = thread::spawn(|| {
INIT.call_once(|| panic!());
});
assert!(handle.join().is_err());
assert!(!INIT.is_completed());Sourcepub fn wait(&self)
pub fn wait(&self)
Blocks the current thread until initialization has completed.
Calling this method from an initialization closure for the same Once
may panic or deadlock.
§Examples
use parking_lot::Once;
use std::thread;
static READY: Once = Once::new();
let thread = thread::spawn(|| {
READY.wait();
println!("everything is ready");
});
READY.call_once(|| println!("performing setup"));
thread.join().unwrap();§Panics
If this Once has been poisoned because an initialization closure has
panicked, this method will also panic. Use
wait_force if this behavior is not desired.
Sourcepub fn wait_force(&self)
pub fn wait_force(&self)
Blocks the current thread until initialization has completed, ignoring poisoning.
If this Once has been poisoned, this function blocks until it becomes
completed, unlike Once::wait, which panics in this case.
Calling this method from an initialization closure for the same Once
may panic or deadlock.
Sourcepub fn call_once<F>(&self, f: F)where
F: FnOnce(),
pub fn call_once<F>(&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_once has 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, the Once is in the completed state. Unless
it was created with new_completed, some
initialization has run and completed, though it might not be the closure
specified. Any memory writes performed by the executed closure can be
reliably observed after this function returns; there is a happens-before
relation between the closure and code executing after the return.
If the given closure recursively invokes call_once on the same Once
instance, the exact behavior is not specified: allowed outcomes are a
panic or a deadlock.
§Examples
use parking_lot::Once;
static mut VAL: usize = 0;
static INIT: Once = 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.
fn get_cached_val() -> usize {
unsafe {
INIT.call_once(|| {
VAL = expensive_computation();
});
VAL
}
}
fn expensive_computation() -> usize {
// ...
}§Panics
The closure f will only be executed once even if this is called
concurrently amongst many threads. If that closure panics, however, then
it will poison this Once instance, causing all future invocations of
call_once to also panic.
Sourcepub fn call_once_force<F>(&self, f: F)
pub fn call_once_force<F>(&self, f: F)
Performs the same function as call_once except it
ignores poisoning.
Unlike call_once, if this Once has been poisoned
by a previous initialization panic, this function will still invoke the
closure f instead of immediately panicking. If f panics, the Once
remains poisoned. If f does not panic, the Once is no longer
poisoned and all future calls to call_once or call_once_force are
no-ops.
The closure f is passed a OnceState which can be used to query the
poison status of this Once.
If the given closure recursively invokes call_once or
call_once_force on the same Once instance, the exact behavior is not
specified: allowed outcomes are a panic or a deadlock.
§Examples
use parking_lot::Once;
use std::thread;
static INIT: Once = Once::new();
// Poison the once.
let handle = thread::spawn(|| {
INIT.call_once(|| panic!());
});
assert!(handle.join().is_err());
// Poisoning propagates.
let handle = thread::spawn(|| {
INIT.call_once(|| {});
});
assert!(handle.join().is_err());
// call_once_force still runs and clears the poisoned state.
INIT.call_once_force(|state| {
assert!(state.is_poisoned());
});
// Once initialization succeeds, future calls are no-ops.
INIT.call_once(|| {});