Skip to main content

BackoffStrategy

Trait BackoffStrategy 

Source
pub trait BackoffStrategy:
    Default
    + Send
    + Sync
    + 'static {
    const BACKOFF: bool = true;

    // Required method
    fn backoff(&mut self) -> RetryStrategy;

    // Provided methods
    fn will_reload(&self) -> bool { ... }
    fn backoff_reload<T: PartialEq, F: FnMut() -> T>(
        &mut self,
        current: T,
        reload: F,
    ) -> T { ... }
    fn backoff_until<C: BackoffUntilCondition, F: FnMut() -> C>(
        &mut self,
        f: F,
    ) -> C::Result { ... }
}
Expand description

Backoff strategy to be used after an atomic compare-and-swap (CAS) failure and in spin loops.

Waiting before retrying a failed CAS can greatly reduce the contention on the atomic’s cache line, and improve the performance of CAS loops.

Spin loops also benefit from backoff as it avoids keeping the CPU 100% busy while waiting, at little latency cost.

Provided Associated Constants§

Source

const BACKOFF: bool = true

Whether the strategy does backoff or not.

Some algorithms may have a different behavior depending on whether backoff is used; for example switching between an unbounded spin loop or a thread parking algorithm. This constant can be used for this purpose.

It should be set to false only for NoBackoff.

Required Methods§

Source

fn backoff(&mut self) -> RetryStrategy

Performs backoff and returns how the CAS should be retried.

will_reload should also be implemented accordingly.

In spin loops, the returned value can simply be ignored.

Provided Methods§

Source

fn will_reload(&self) -> bool

Returns true if the next call to backoff will not return RetryStrategy::NoReload.

This hint can be used to downgrade the failure ordering of the CAS to Relaxed when the returned value is overwritten anyway.

Source

fn backoff_reload<T: PartialEq, F: FnMut() -> T>( &mut self, current: T, reload: F, ) -> T

Performs backoff after a failed CAS and reloads the atomic value according to the returned RetryStrategy.

ReloadUntilUnchanged causes this function to loop until the value stops changing. If the value returned by the failed CAS must be tested between reloads, use BackoffState instead.

§Example
fn update_with_backoff(
    atomic: &AtomicUsize,
    set_order: Ordering,
    fetch_order: Ordering,
    mut f: impl FnMut(usize) -> usize,
    mut strategy: impl BackoffStrategy,
) -> usize {
    let mut current = atomic.load(fetch_order);
    loop {
        let failure_order = if strategy.will_reload() {
            Ordering::Relaxed
        } else {
            fetch_order
        };
        match atomic.compare_exchange_weak(current, f(current), set_order, failure_order) {
            Ok(x) => return x,
            Err(cur) => current = strategy.backoff_reload(cur, || atomic.load(fetch_order)),
        }
    }
}
Source

fn backoff_until<C: BackoffUntilCondition, F: FnMut() -> C>( &mut self, f: F, ) -> C::Result

Loops until a condition is satisfied, performing backoff at each iteration.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§

Source§

impl BackoffStrategy for NoBackoff

Source§

const BACKOFF: bool = false

Source§

impl BackoffStrategy for SpinBackoff

Source§

impl<S: BackoffStrategy, const LIMIT: usize> BackoffStrategy for BackoffLimit<S, LIMIT>

Source§

const BACKOFF: bool = S::BACKOFF

Source§

impl<const SPIN_LIMIT: usize, const UNTIL_UNCHANGED_LIMIT: usize, const YIELD_AFTER: usize> BackoffStrategy for ExponentialBackoff<SPIN_LIMIT, UNTIL_UNCHANGED_LIMIT, YIELD_AFTER>