Struct rsevents_extra::CountdownEvent
source · 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
impl CountdownEvent
sourcepub const fn new(count: usize) -> Self
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?
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!");
});
}
sourcepub fn decrement(&self)
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).
sourcepub fn tick(&self)
pub fn tick(&self)
An alias for decrement()
for backwards compatibility purposes.
Examples found in repository?
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!");
});
}
sourcepub fn increment(&self)
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.
sourcepub fn reset(&self, count: usize)
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.
sourcepub fn count(&self) -> usize
pub fn count(&self) -> usize
Get the current internal countdown value.
Examples found in repository?
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
impl Awaitable<'_> for CountdownEvent
source§fn try_wait(&self) -> Result<(), Infallible>
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>
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>
fn try_wait0(&self) -> Result<(), TimeoutError>
An optimized (wait-free, lock-free) check to see if the CountdownEvent
has reached zero or
not.
§type Error = TimeoutError
type Error = TimeoutError
Awaitable::wait()
returns any error at all.source§fn wait(&'a self) -> Self::Twhere
Self::Error: InfallibleUnboundedWait,
fn wait(&'a self) -> Self::Twhere Self::Error: InfallibleUnboundedWait,
Awaitable
type and its associated type T
become available. Like
try_wait()
but bypasses error handling. Read moresource§fn wait_for(&'a self, limit: Duration) -> boolwhere
Self: VoidAwaitable,
Self::Error: InfallibleUnboundedWait,
fn wait_for(&'a self, limit: Duration) -> boolwhere Self: VoidAwaitable, Self::Error: InfallibleUnboundedWait,
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 moresource§fn wait0(&'a self) -> boolwhere
Self: VoidAwaitable,
Self::Error: InfallibleUnboundedWait,
fn wait0(&'a self) -> boolwhere Self: VoidAwaitable, Self::Error: InfallibleUnboundedWait,
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