pub struct TaskQueue<H: Handle> { /* private fields */ }Expand description
A concurrent work-stealing queue that manages a set of Tasks.
Workers created by Executor::execute call steal to obtain
new work when their current task is exhausted. The queue supports splitting,
speculative execution, and dynamic thread adjustment.
Implementations§
Source§impl<H: Handle> TaskQueue<H>
impl<H: Handle> TaskQueue<H>
Sourcepub fn new(tasks: impl Iterator<Item = Range<u64>>) -> Self
pub fn new(tasks: impl Iterator<Item = Range<u64>>) -> Self
Creates a queue from an iterator of start..end ranges, each wrapped in its
own Task.
Sourcepub fn add(&self, task: Task) -> bool
pub fn add(&self, task: Task) -> bool
Appends a Task to the waiting queue so a future
steal or set_threads can
pick it up.
Returns true if at least one worker is currently registered and live
(so the task will be picked up on that worker’s next steal), or
false if no live worker exists — in which case the task stays stranded
in waiting until a set_threads call spawns a
worker to rescue it.
Sourcepub fn steal(
&self,
id: &H::Id,
task: &mut Task,
min_chunk_size: u64,
max_speculative: usize,
) -> bool
pub fn steal( &self, id: &H::Id, task: &mut Task, min_chunk_size: u64, max_speculative: usize, ) -> bool
Tries to refill task with more work for the worker identified by id.
The caller must pass its own currently-held Task plus id (compared via
Handle::is_self). The function first hands out a
pending task from the waiting queue; if none is available it steals a half
range from the busiest running task via Task::split_two
(when at least min_chunk_size * 2 work remains), or, if max_speculative > 1
and the stolen task has few enough strong references, shares that same task
speculatively.
Returns true if task was refilled, or false if the worker is not
registered or no work could be found.
Sourcepub fn set_threads<E: Executor<Handle = H>>(
&self,
threads: usize,
min_chunk_size: u64,
executor: Option<&E>,
) -> Option<()>
pub fn set_threads<E: Executor<Handle = H>>( &self, threads: usize, min_chunk_size: u64, executor: Option<&E>, ) -> Option<()>
Returns None when threads need to be increased but the executor is None
Sourcepub fn handles<F, R>(&self, f: F) -> R
pub fn handles<F, R>(&self, f: F) -> R
Provides mutable access to the handles of all running tasks, e.g. to abort or inspect them.
§Liveness / deadlock contract
The closure f is invoked while the queue lock is held. It must not
re-enter TaskQueue (e.g. call steal,
add, set_threads, or
handles again) — doing so deadlocks. Keep f
short: it blocks every other queue operation until it returns.
Sourcepub fn cancel_task(&self, task: &Task, id: &H::Id)
pub fn cancel_task(&self, task: &Task, id: &H::Id)
Aborts every running task equal to task that does not belong to the
worker id.
The call is a no-op unless id identifies a currently registered worker.
An unregistered caller matches no entry in running, which makes the
is_self guard vacuous: every twin would be aborted, including the one
that should survive, leaving work in waiting with no worker to claim it.
A caller can legitimately reach this state after a
set_threads shrink deregisters it, because the
abort that follows is cooperative and the worker keeps running until it
observes the signal.
Aborted twins are deregistered (removed from running) so a later
set_threads liveness sweep does not mistake
them for live workers. Their remaining work is not reclaimed into
waiting: the aborted twins matched t == *task, i.e. they alias the
caller’s cursor, so the caller’s own still-live task already owns and
advances that remaining range. Reclaiming would only add a redundant
waiting entry — the take handshake that steal applies to a shared
cursor partitions it atomically, so a reclaimed twin would not execute
the same bytes twice. The production caller fast-pull therefore invokes
this only after the shared range has finished, letting the caller’s task
carry the work to completion.