pub struct CountdownEvent { /* private fields */ }
Expand description

An Awaitable type that can be used to block until n parallel tasks have completed.

A countdown event is a special type of ManualResetEvent that makes it easy to wait for a given number of tasks to complete asynchronously, and then carry out some action. A countdown event is first initialized with a count equal to the number of outstanding tasks, and each time a task is completed, CountdownEvent::tick() is called. A call to CountdownEvent::wait() will block until all outstanding tasks have completed and the internal counter reaches 0.

Countdown events are thread-safe and may be declared as static variables or wrapped in an Arc to easily share across threads.

Example:

use rsevents_extra::{Awaitable, CountdownEvent};

// CountdownEvent::new() is const and can be used directly in a static
// context without needing lazy_static or once_cell:
static ALMOST_DONE: CountdownEvent = CountdownEvent::new(0);

fn worker_thread() {
    for _ in 0..250 {
        // <Do something really important...>

        // Each time we've finished a task, report our progress against
        // the countdown event.
        // Note that it's OK to keep calling this after the countdown
        // event has already fired.
        ALMOST_DONE.tick();
    }
}

fn main() {
    // Re-init the countdown event to fire after the first 750 tasks have
    // been completed.
    ALMOST_DONE.reset(750);

    // Start 4 threads to begin work in parallel
    std::thread::scope(|scope| {
        for _ in 0..4 {
            scope.spawn(worker_thread);
        }

        // Wait for the 750 tasks to be finished. This gives us more
        // freedom than blocking until all threads have exited (as they may
        // be long-lived and service many different tasks of different
        // types, each of which we could track separately.)
        ALMOST_DONE.wait();

        eprintln!("Worker threads have almost finished! Hang tight!");
    });
}

Implementations§

source§

impl CountdownEvent

source

pub const fn new(count: usize) -> Self

Creates a new countdown event with the internal count initialized to count. If a count of zero is specified, the event is immediately set.

This is a const function and can be used in a static context, (e.g. to declare a shared, static variable without using lazy_static or once_cell).

Examples found in repository?
examples/countdown.rs (line 6)
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
fn main() {
    let countdown = CountdownEvent::new(42);

    thread::scope(|scope| {
        // Start two worker threads to each do some of the work
        for i in 0..2 {
            // Shadow some variables to allow us to `move` into the closure
            let i = i;
            let countdown = &countdown;

            scope.spawn(move || {
                println!("Worker thread reporting for duty!");

                // Worker thread will pretend to do some work
                for i in (500 * i)..(280 * (i + 1)) {
                    if i % 7 == 3 {
                        countdown.tick();
                    }

                    thread::sleep(Duration::from_millis(18));
                }
            });
        }

        // The main thread will wait for 42 tasks to be completed before it does
        // its thing... whatever that is.
        while !countdown.wait_for(Duration::from_secs(1)) {
            // Report progress every 1 second until we've finished
            eprintln!("Work in progress. {} items remaining.", countdown.count());
        }

        eprintln!("Work completed!");
    });
}
source

pub fn decrement(&self)

Decrements the internal countdown. When the internal countdown reaches zero, the countdown event enters a set state and any outstanding or future calls to CountdownEvent::wait() will be let through without blocking (until the event is reset or incremented).

source

pub fn tick(&self)

An alias for decrement() for backwards compatibility purposes.

Examples found in repository?
examples/countdown.rs (line 21)
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
fn main() {
    let countdown = CountdownEvent::new(42);

    thread::scope(|scope| {
        // Start two worker threads to each do some of the work
        for i in 0..2 {
            // Shadow some variables to allow us to `move` into the closure
            let i = i;
            let countdown = &countdown;

            scope.spawn(move || {
                println!("Worker thread reporting for duty!");

                // Worker thread will pretend to do some work
                for i in (500 * i)..(280 * (i + 1)) {
                    if i % 7 == 3 {
                        countdown.tick();
                    }

                    thread::sleep(Duration::from_millis(18));
                }
            });
        }

        // The main thread will wait for 42 tasks to be completed before it does
        // its thing... whatever that is.
        while !countdown.wait_for(Duration::from_secs(1)) {
            // Report progress every 1 second until we've finished
            eprintln!("Work in progress. {} items remaining.", countdown.count());
        }

        eprintln!("Work completed!");
    });
}
source

pub fn increment(&self)

Increment the internal count (e.g. to add a work item).

This resets the event (makes it unavailable) if the previous count was zero.

source

pub fn reset(&self, count: usize)

Resets a countdown event to the specified count. If a count of zero is specified, the countdown event is immediately set.

source

pub fn count(&self) -> usize

Get the current internal countdown value.

Examples found in repository?
examples/countdown.rs (line 33)
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
fn main() {
    let countdown = CountdownEvent::new(42);

    thread::scope(|scope| {
        // Start two worker threads to each do some of the work
        for i in 0..2 {
            // Shadow some variables to allow us to `move` into the closure
            let i = i;
            let countdown = &countdown;

            scope.spawn(move || {
                println!("Worker thread reporting for duty!");

                // Worker thread will pretend to do some work
                for i in (500 * i)..(280 * (i + 1)) {
                    if i % 7 == 3 {
                        countdown.tick();
                    }

                    thread::sleep(Duration::from_millis(18));
                }
            });
        }

        // The main thread will wait for 42 tasks to be completed before it does
        // its thing... whatever that is.
        while !countdown.wait_for(Duration::from_secs(1)) {
            // Report progress every 1 second until we've finished
            eprintln!("Work in progress. {} items remaining.", countdown.count());
        }

        eprintln!("Work completed!");
    });
}

Trait Implementations§

source§

impl Awaitable<'_> for CountdownEvent

source§

fn try_wait(&self) -> Result<(), Infallible>

Waits for the internal countdown of the CountdownEvent to reach zero.

source§

fn try_wait_for(&self, limit: Duration) -> Result<(), TimeoutError>

Waits for the internal countdown of the CountdownEvent to reach zero or returns an error in case of a timeout.

source§

fn try_wait0(&self) -> Result<(), TimeoutError>

An optimized (wait-free, lock-free) check to see if the CountdownEvent has reached zero or not.

§

type T = ()

The type yielded by the Awaitable type on a successful wait
§

type Error = TimeoutError

The type yielded by the Awaitable type in case of an error, also specifying whether or not an unbounded Awaitable::wait() returns any error at all.
source§

fn wait(&'a self) -> Self::Twhere Self::Error: InfallibleUnboundedWait,

Blocks until the Awaitable type and its associated type T become available. Like try_wait() but bypasses error handling. Read more
source§

fn wait_for(&'a self, limit: Duration) -> boolwhere Self: VoidAwaitable, Self::Error: InfallibleUnboundedWait,

Attempts a bounded wait on the the Awaitable type. Like try_wait_for() but returns true if the Awaitable was originally available or if it became so within the specified duration and false otherwise. Read more
source§

fn wait0(&'a self) -> boolwhere Self: VoidAwaitable, Self::Error: InfallibleUnboundedWait,

Attempts to obtain the Awaitable in a potentially lock-free, wait-free manner, returning a timeout error if it’s currently unavailable. Like try_wait0() but returns true if the Awaitable was available and obtained or false otherwise. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

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

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

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

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere 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 Twhere 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 Twhere U: Into<T>,

§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

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

§

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.