Skip to main content

Once

Struct Once 

Source
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

Source

pub const fn new() -> Once

Creates a new Once value.

Source

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!());
Source

pub fn state(&self) -> OnceState

Returns a snapshot of the current state of this Once.

The state may change immediately after this function returns.

Source

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());
Source

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.

Source

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.

Source

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.

Source

pub fn call_once_force<F>(&self, f: F)
where F: FnOnce(OnceState),

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(|| {});

Trait Implementations§

Source§

impl Debug for Once

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Once

Source§

fn default() -> Once

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

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

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.