Class Scheduler

Nested Relationships

Nested Types

Class Documentation

class Scheduler

Work-stealing scheduler for Job<T> coroutines.

The Scheduler manages a pool of worker threads that execute Job<T> coroutines in parallel. It implements a work-stealing algorithm where each worker has a local queue, and idle workers can steal jobs from busy workers to achieve load balancing.

Dispatch vs Wait:

  • dispatch_job(s): Fire-and-forget async execution (returns immediately)

  • wait_for_job(s): Dispatch and block until complete, returning results

  • wait_for_counter: Block until counter reaches zero (fork-join sync)

Job Priority:

  • High: Processed before Normal priority jobs

  • Normal: Standard execution priority

  • Low: Processed after Normal priority jobs

Example (Basic Usage):

// Create scheduler with hardware_concurrency - 1 workers
Scheduler scheduler(-1);

// Wait for single job (blocking)
int result = scheduler.wait_for_job(compute_value());

// Dispatch multiple jobs async
Counter counter{};
for (int i = 0; i < 100; i++)
    scheduler.dispatch_job(process_item(i), JobPriority::Normal, &counter);
scheduler.wait_for_counter(counter);

See also

Job for the coroutine type

See also

Counter for fork-join synchronization

Note

Scheduler is not copyable or movable (owns worker threads)

Note

All jobs must complete before Scheduler destruction

Public Functions

explicit Scheduler(int32_t num_worker_threads, size_t job_cache_size = WorkerContext::CACHE_SIZE)

Create scheduler with specified number of worker threads.

Parameters:
  • num_worker_threads – Worker count:

    • 0: No workers, main thread only

    • n: Exactly n worker threads

    • -1: Hardware concurrency - 1

  • job_cache_size – Per-worker job cache size (default 4)

~Scheduler()
Scheduler(const Scheduler&) = delete
Scheduler &operator=(const Scheduler&) = delete
Scheduler &operator=(Scheduler&&) = delete
void wait_for_counter(Counter &counter)

Block until counter reaches zero (fork-join synchronization).

Parameters:

counterCounter to wait on

void wait_for_jobs(std::span<JobBase> jobs, JobPriority priority = JobPriority::Normal)

Dispatch jobs and block until all complete.

Parameters:
  • jobs – Span of type-erased jobs to execute

  • priority – Execution priority (High, Normal, or Low)

template<typename ...Results>
std::tuple<std::expected<Results, JobResultStatus>...> wait_for_jobs(std::tuple<Job<Results>...> jobs, const JobPriority priority = JobPriority::Normal)

Dispatch tuple of jobs and block until all complete, returning their results.

Template Parameters:

Results – Return types of the jobs in the tuple

Parameters:
  • jobs – Tuple of Job<T> coroutines

  • priority – Execution priority

Returns:

Tuple of std::expected<T, JobResultStatus> results

template<typename ...Results>
std::tuple<std::expected<Results, JobResultStatus>...> wait_for_jobs(Job<Results>... jobs, const JobPriority priority = JobPriority::Normal)

Dispatch variadic jobs and block until all complete, returning their results.

Template Parameters:

Results – Return types of the jobs

Parameters:
  • jobs – Variadic pack of Job<T> coroutines

  • priority – Execution priority

Returns:

Tuple of std::expected<T, JobResultStatus> results

template<typename Result>
auto wait_for_jobs(const std::span<Job<Result>> jobs, const JobPriority priority = JobPriority::Normal)

Dispatch span of jobs and block until all complete, collecting non-void results.

Template Parameters:

Result – Return type of the jobs

Parameters:
  • jobs – Span of Job<Result> coroutines

  • priority – Execution priority

Returns:

SmallVector of results

template<typename Result>
void wait_for_jobs(const std::span<Job<Result>> jobs, const JobPriority priority = JobPriority::Normal)

Dispatch span of void jobs and block until all complete.

Template Parameters:

Result – Must be void

Parameters:
  • jobs – Span of Job<void> coroutines

  • priority – Execution priority

template<typename Result>
void wait_for_job(Job<Result> job, const JobPriority priority = JobPriority::Normal)

Dispatch single void job and block until complete.

Template Parameters:

Result – Must be void

Parameters:
  • jobJob<void> coroutine

  • priority – Execution priority

template<typename Result>
Result wait_for_job(Job<Result> job, const JobPriority priority = JobPriority::Normal)

Dispatch single job and block until complete, returning result.

Template Parameters:

Result – Return type of the job

Parameters:
  • job – Job<Result> coroutine

  • priority – Execution priority

Returns:

The job’s result value

void dispatch_jobs(std::span<JobBase> jobs, JobPriority priority = JobPriority::Normal, Counter *counter = nullptr)

Dispatch jobs for async execution without blocking.

Parameters:
  • jobs – Span of type-erased jobs

  • priority – Execution priority

  • counter – Optional counter to track completion

void dispatch_job(JobBase job, JobPriority priority = JobPriority::Normal, Counter *counter = nullptr)

Dispatch single job for async execution without blocking.

Parameters:
  • job – Type-erased job to execute

  • priority – Execution priority

  • counter – Optional counter to track completion

template<typename ...Results>
void dispatch_jobs(std::tuple<Job<Results...>> jobs, const JobPriority priority = JobPriority::Normal, Counter *counter = nullptr)

Dispatch tuple of jobs for async execution without blocking.

Template Parameters:

Results – Return types of the jobs

Parameters:
  • jobs – Tuple of Job<T> coroutines

  • priority – Execution priority

  • counter – Optional counter to track completion

template<typename Result>
void dispatch_jobs(std::span<Job<Result>> jobs, JobPriority priority = JobPriority::Normal, Counter *counter = nullptr)

Dispatch span of jobs for async execution without blocking.

Template Parameters:

Result – Return type of the jobs

Parameters:
  • jobs – Span of Job<Result> coroutines

  • priority – Execution priority

  • counter – Optional counter to track completion

template<typename Result>
void dispatch_job(Job<Result> job, JobPriority priority = JobPriority::Normal, Counter *counter = nullptr)

Dispatch single typed job for async execution without blocking.

Template Parameters:

Result – Return type of the job

Parameters:
  • job – Job<Result> coroutine

  • priority – Execution priority

  • counter – Optional counter to track completion

inline JobStats &get_stats()
inline const JobStats &get_stats() const
WorkerIterationState main_thread_do_work()

Process one job from main thread

Returns:

State indicating whether work was executed, cache filled, or queue empty

Public Static Functions

static inline size_t get_tls_worker_id()
struct WorkerContext

Per-worker execution context with local queue and job cache.

Public Members

WorkerQueue queue
std::mt19937 rng = {std::random_device{}()}
size_t worker_id
std::vector<JobBase::handle_type> job_cache
size_t cache_index = 0
uint32_t iterations_since_steal_check = 0
uint32_t iterations_since_sample = 0

Public Static Attributes

static constexpr size_t CACHE_SIZE = 4
static constexpr uint32_t STEAL_CHECK_INTERVAL = 128
static constexpr uint32_t SAMPLE_INTERVAL = 1000