Helios Engine 0.1.0
A modular ECS based data-oriented C++23 game engine
 
Loading...
Searching...
No Matches
helios::async::Executor Class Reference

Manages worker threads and executes task graphs using work-stealing scheduling. More...

#include <executor.hpp>

Public Member Functions

 Executor ()=default
 
 Executor (size_t worker_thread_count)
 Constructs an executor with the specified number of worker threads.
 
 Executor (const Executor &)=delete
 
 Executor (Executor &&)=delete
 
 ~Executor ()=default
 
Executoroperator= (const Executor &)=delete
 
Executoroperator= (Executor &&)=delete
 
auto Run (TaskGraph &graph) -> Future< void >
 Runs a task graph once.
 
auto Run (TaskGraph &&graph) -> Future< void >
 Runs a moved task graph once.
 
template<std::invocable C>
auto Run (TaskGraph &graph, C &&callable) -> Future< void >
 Runs a task graph once and invokes a callback upon completion.
 
template<std::invocable C>
auto Run (TaskGraph &&graph, C &&callable) -> Future< void >
 Runs a moved task graph once and invokes a callback upon completion.
 
auto RunN (TaskGraph &graph, size_t count) -> Future< void >
 Runs a task graph for the specified number of times.
 
auto RunN (TaskGraph &&graph, size_t count) -> Future< void >
 Runs a moved task graph for the specified number of times.
 
template<std::invocable C>
auto RunN (TaskGraph &graph, size_t count, C &&callable) -> Future< void >
 Runs a task graph for the specified number of times and invokes a callback.
 
template<std::invocable C>
auto RunN (TaskGraph &&graph, size_t count, C &&callable) -> Future< void >
 Runs a moved task graph for the specified number of times and invokes a callback.
 
template<std::predicate Predicate>
auto RunUntil (TaskGraph &graph, Predicate &&predicate) -> Future< void >
 Runs a task graph repeatedly until the predicate returns true.
 
template<std::predicate Predicate>
auto RunUntil (TaskGraph &&graph, Predicate &&predicate) -> Future< void >
 Runs a moved task graph repeatedly until the predicate returns true.
 
template<std::predicate Predicate, std::invocable C>
auto RunUntil (TaskGraph &graph, Predicate &&predicate, C &&callable) -> Future< void >
 Runs a task graph repeatedly until the predicate returns true, then invokes a callback.
 
template<std::predicate Predicate, std::invocable C>
auto RunUntil (TaskGraph &&graph, Predicate &&predicate, C &&callable) -> Future< void >
 Runs a moved task graph repeatedly until the predicate returns true, then invokes a callback.
 
template<std::invocable C>
auto Async (C &&callable) -> std::future< std::invoke_result_t< C > >
 Creates an asynchronous task that runs the given callable.
 
template<std::invocable C>
auto Async (std::string name, C &&callable) -> std::future< std::invoke_result_t< C > >
 Creates a named asynchronous task that runs the given callable.
 
template<std::invocable C>
void SilentAsync (C &&callable)
 Creates an asynchronous task without returning a future.
 
template<std::invocable C>
void SilentAsync (std::string name, C &&callable)
 Creates a named asynchronous task without returning a future.
 
template<std::invocable C, std::ranges::range Dependencies>
requires std::same_as<std::ranges::range_value_t<Dependencies>, AsyncTask>
auto DependentAsync (C &&callable, const Dependencies &dependencies) -> std::pair< AsyncTask, std::future< std::invoke_result_t< C > > >
 Creates an asynchronous task that runs after specified dependencies complete.
 
template<std::invocable C, std::ranges::range Dependencies>
requires std::same_as<std::ranges::range_value_t<Dependencies>, AsyncTask>
AsyncTask SilentDependentAsync (C &&callable, const Dependencies &dependencies)
 Creates an asynchronous task that runs after dependencies complete, without returning a future.
 
void WaitForAll ()
 Blocks until all submitted tasks complete.
 
void CoRun (TaskGraph &graph)
 Runs a task graph cooperatively and waits until it completes using the current worker thread.
 
template<std::predicate Predicate>
void CoRunUntil (Predicate &&predicate)
 Keeps the current worker thread running until the predicate returns true.
 
bool IsWorkerThread () const
 Checks if the current thread is a worker thread of this executor.
 
int CurrentWorkerId () const
 Gets the ID of the current worker thread.
 
size_t WorkerCount () const noexcept
 Gets the total number of worker threads.
 
size_t IdleWorkerCount () const noexcept
 Gets the number of worker threads currently waiting for work.
 
size_t QueueCount () const noexcept
 Gets the number of task queues in the work-stealing scheduler.
 
size_t RunningTopologyCount () const
 Gets the number of task graphs currently being executed.
 

Detailed Description

Manages worker threads and executes task graphs using work-stealing scheduling.

The Executor wraps tf::Executor and provides methods to run TaskGraphs and create asynchronous tasks. It manages a pool of worker threads that efficiently execute tasks using a work-stealing algorithm.

Note
All member functions are thread-safe unless otherwise noted.

Definition at line 33 of file executor.hpp.

Constructor & Destructor Documentation

◆ Executor() [1/4]

helios::async::Executor::Executor ( )
default

Default constructs an executor with hardware concurrency worker threads.

◆ Executor() [2/4]

helios::async::Executor::Executor ( size_t  worker_thread_count)
inlineexplicit

Constructs an executor with the specified number of worker threads.

Parameters
worker_thread_countNumber of worker threads to create

Definition at line 42 of file executor.hpp.

42: executor_(worker_thread_count) {}

◆ Executor() [3/4]

helios::async::Executor::Executor ( const Executor )
delete

◆ Executor() [4/4]

helios::async::Executor::Executor ( Executor &&  )
delete

◆ ~Executor()

helios::async::Executor::~Executor ( )
default

Member Function Documentation

◆ Async() [1/2]

template<std::invocable C>
auto helios::async::Executor::Async ( C &&  callable) -> std::future<std::invoke_result_t<C>>
inline

Creates an asynchronous task that runs the given callable.

The task is scheduled immediately and runs independently.

Note
Thread-safe.
Template Parameters
CCallable type
Parameters
callableFunction to execute asynchronously
Returns
Future that will hold the result of the execution

Definition at line 225 of file executor.hpp.

225 {
226 return executor_.async(std::forward<C>(callable));
227 }

◆ Async() [2/2]

template<std::invocable C>
auto helios::async::Executor::Async ( std::string  name,
C &&  callable 
) -> std::future<std::invoke_result_t<C>>
inline

Creates a named asynchronous task that runs the given callable.

The task is scheduled immediately and runs independently.

Note
Thread-safe.
Template Parameters
CCallable type
Parameters
nameName for the task (useful for debugging/profiling)
callableFunction to execute asynchronously
Returns
Future that will hold the result of the execution

Definition at line 365 of file executor.hpp.

365 {
366 tf::TaskParams params;
367 params.name = std::move(name);
368 return executor_.async(params, std::forward<C>(callable));
369}

◆ CoRun()

void helios::async::Executor::CoRun ( TaskGraph graph)
inline

Runs a task graph cooperatively and waits until it completes using the current worker thread.

Warning
Must be called from within a worker thread of this executor. Triggers assertion if called from a non-worker thread.
Parameters
graphTask graph to execute

Definition at line 410 of file executor.hpp.

410 {
411 HELIOS_ASSERT(IsWorkerThread(), "Failed to co-run: Must be called from a worker thread");
412 executor_.corun(graph.UnderlyingTaskflow());
413}
#define HELIOS_ASSERT(condition,...)
Assertion macro that aborts execution in debug builds.
Definition assert.hpp:140
bool IsWorkerThread() const
Checks if the current thread is a worker thread of this executor.
Definition executor.hpp:323

◆ CoRunUntil()

template<std::predicate Predicate>
void helios::async::Executor::CoRunUntil ( Predicate &&  predicate)
inline

Keeps the current worker thread running until the predicate returns true.

Warning
Must be called from within a worker thread of this executor. Triggers assertion if called from a non-worker thread.
Template Parameters
PredicatePredicate type
Parameters
predicateBoolean predicate to determine when to stop

Definition at line 416 of file executor.hpp.

416 {
417 HELIOS_ASSERT(IsWorkerThread(), "Failed to co-run until: Must be called from a worker thread");
418 executor_.corun_until(std::forward<Predicate>(predicate));
419}

◆ CurrentWorkerId()

int helios::async::Executor::CurrentWorkerId ( ) const
inline

Gets the ID of the current worker thread.

Note
Thread-safe.
Returns
Worker ID (0 to N-1) or -1 if not a worker thread

Definition at line 330 of file executor.hpp.

330{ return executor_.this_worker_id(); }

◆ DependentAsync()

template<std::invocable C, std::ranges::range Dependencies>
requires std::same_as<std::ranges::range_value_t<Dependencies>, AsyncTask>
auto helios::async::Executor::DependentAsync ( C &&  callable,
const Dependencies &  dependencies 
) -> std::pair<AsyncTask, std::future<std::invoke_result_t<C>>>
inline

Creates an asynchronous task that runs after specified dependencies complete.

The task will only execute after all dependencies finish.

Note
Thread-safe.
Template Parameters
CCallable type
DependenciesRange type containing AsyncTask dependencies
Parameters
callableFunction to execute asynchronously
dependenciesTasks that must complete before this task runs
Returns
Pair containing AsyncTask handle and Future for the result

Definition at line 380 of file executor.hpp.

381 {
382 std::vector<tf::AsyncTask> tf_deps;
383 if constexpr (std::ranges::sized_range<Dependencies>) {
384 tf_deps.reserve(std::ranges::size(dependencies));
385 }
386
387 for (const auto& dep : dependencies) {
388 tf_deps.push_back(dep.UnderlyingTask());
389 }
390
391 auto [task, future] = executor_.dependent_async(std::forward<C>(callable), tf_deps.begin(), tf_deps.end());
392 return std::make_pair(AsyncTask(std::move(task)), std::move(future));
393}

◆ IdleWorkerCount()

size_t helios::async::Executor::IdleWorkerCount ( ) const
inlinenoexcept

Gets the number of worker threads currently waiting for work.

Note
Thread safe.
Returns
Count of idle worker threads

Definition at line 344 of file executor.hpp.

344{ return executor_.num_waiters(); }

◆ IsWorkerThread()

bool helios::async::Executor::IsWorkerThread ( ) const
inline

Checks if the current thread is a worker thread of this executor.

Note
Thread safe.
Returns
True if current thread is a worker, false otherwise

Definition at line 323 of file executor.hpp.

323{ return CurrentWorkerId() != -1; }
int CurrentWorkerId() const
Gets the ID of the current worker thread.
Definition executor.hpp:330

◆ operator=() [1/2]

Executor & helios::async::Executor::operator= ( const Executor )
delete

◆ operator=() [2/2]

Executor & helios::async::Executor::operator= ( Executor &&  )
delete

◆ QueueCount()

size_t helios::async::Executor::QueueCount ( ) const
inlinenoexcept

Gets the number of task queues in the work-stealing scheduler.

Note
Thread safe.
Returns
Count of task queues

Definition at line 351 of file executor.hpp.

351{ return executor_.num_queues(); }

◆ Run() [1/4]

auto helios::async::Executor::Run ( TaskGraph &&  graph) -> Future<void>
inline

Runs a moved task graph once.

The executor takes ownership of the moved graph.

Note
Thread-safe.
Parameters
graphTask graph to execute (moved)
Returns
Future that completes when execution finishes

Definition at line 66 of file executor.hpp.

66 {
67 return Future<void>(executor_.run(std::move(std::move(graph).UnderlyingTaskflow())));
68 }

◆ Run() [2/4]

template<std::invocable C>
auto helios::async::Executor::Run ( TaskGraph &&  graph,
C &&  callable 
) -> Future<void>
inline

Runs a moved task graph once and invokes a callback upon completion.

The executor takes ownership of the moved graph.

Note
Thread-safe.
Template Parameters
CCallable type
Parameters
graphTask graph to execute (moved)
callableCallback to invoke after execution completes
Returns
Future that completes when execution finishes

Definition at line 94 of file executor.hpp.

94 {
95 return Future<void>(executor_.run(std::move(std::move(graph).UnderlyingTaskflow()), std::forward<C>(callable)));
96 }

◆ Run() [3/4]

auto helios::async::Executor::Run ( TaskGraph graph) -> Future<void>
inline

Runs a task graph once.

The executor does not own the graph - ensure it remains alive during execution.

Note
Thread-safe.
Parameters
graphTask graph to execute
Returns
Future that completes when execution finishes

Definition at line 57 of file executor.hpp.

57{ return Future<void>(executor_.run(graph.UnderlyingTaskflow())); }

◆ Run() [4/4]

template<std::invocable C>
auto helios::async::Executor::Run ( TaskGraph graph,
C &&  callable 
) -> Future<void>
inline

Runs a task graph once and invokes a callback upon completion.

The executor does not own the graph - ensure it remains alive during execution.

Note
Thread-safe.
Template Parameters
CCallable type
Parameters
graphTask graph to execute
callableCallback to invoke after execution completes
Returns
Future that completes when execution finishes

Definition at line 80 of file executor.hpp.

80 {
81 return Future<void>(executor_.run(graph.UnderlyingTaskflow(), std::forward<C>(callable)));
82 }

◆ RunN() [1/4]

auto helios::async::Executor::RunN ( TaskGraph &&  graph,
size_t  count 
) -> Future<void>
inline

Runs a moved task graph for the specified number of times.

The executor takes ownership of the moved graph.

Note
Thread-safe.
Parameters
graphTask graph to execute (moved)
countNumber of times to run the graph
Returns
Future that completes when all executions finish

Definition at line 118 of file executor.hpp.

118 {
119 return Future<void>(executor_.run_n(std::move(std::move(graph).UnderlyingTaskflow()), count));
120 }

◆ RunN() [2/4]

template<std::invocable C>
auto helios::async::Executor::RunN ( TaskGraph &&  graph,
size_t  count,
C &&  callable 
) -> Future<void>
inline

Runs a moved task graph for the specified number of times and invokes a callback.

The executor takes ownership of the moved graph.

Note
Thread-safe.
Template Parameters
CCallable type
Parameters
graphTask graph to execute (moved)
countNumber of times to run the graph
callableCallback to invoke after all executions complete
Returns
Future that completes when all executions finish

Definition at line 148 of file executor.hpp.

148 {
149 return Future<void>(
150 executor_.run_n(std::move(std::move(graph).UnderlyingTaskflow()), count, std::forward<C>(callable)));
151 }

◆ RunN() [3/4]

auto helios::async::Executor::RunN ( TaskGraph graph,
size_t  count 
) -> Future<void>
inline

Runs a task graph for the specified number of times.

The executor does not own the graph - ensure it remains alive during execution.

Note
Thread-safe.
Parameters
graphTask graph to execute
countNumber of times to run the graph
Returns
Future that completes when all executions finish

Definition at line 106 of file executor.hpp.

106 {
107 return Future<void>(executor_.run_n(graph.UnderlyingTaskflow(), count));
108 }

◆ RunN() [4/4]

template<std::invocable C>
auto helios::async::Executor::RunN ( TaskGraph graph,
size_t  count,
C &&  callable 
) -> Future<void>
inline

Runs a task graph for the specified number of times and invokes a callback.

The executor does not own the graph - ensure it remains alive during execution.

Note
Thread-safe.
Template Parameters
CCallable type
Parameters
graphTask graph to execute
countNumber of times to run the graph
callableCallback to invoke after all executions complete
Returns
Future that completes when all executions finish

Definition at line 133 of file executor.hpp.

133 {
134 return Future<void>(executor_.run_n(graph.UnderlyingTaskflow(), count, std::forward<C>(callable)));
135 }

◆ RunningTopologyCount()

size_t helios::async::Executor::RunningTopologyCount ( ) const
inline

Gets the number of task graphs currently being executed.

Note
Thread safe.
Returns
Count of running task graphs

Definition at line 358 of file executor.hpp.

358{ return executor_.num_topologies(); }

◆ RunUntil() [1/4]

template<std::predicate Predicate>
auto helios::async::Executor::RunUntil ( TaskGraph &&  graph,
Predicate &&  predicate 
) -> Future<void>
inline

Runs a moved task graph repeatedly until the predicate returns true.

The executor takes ownership of the moved graph.

Note
Thread-safe.
Template Parameters
PredicatePredicate type
Parameters
graphTask graph to execute (moved)
predicateBoolean predicate to determine when to stop
Returns
Future that completes when predicate returns true

Definition at line 177 of file executor.hpp.

177 {
178 return Future<void>(
179 executor_.run_until(std::move(std::move(graph).UnderlyingTaskflow()), std::forward<Predicate>(predicate)));
180 }

◆ RunUntil() [2/4]

template<std::predicate Predicate, std::invocable C>
auto helios::async::Executor::RunUntil ( TaskGraph &&  graph,
Predicate &&  predicate,
C &&  callable 
) -> Future<void>
inline

Runs a moved task graph repeatedly until the predicate returns true, then invokes a callback.

The executor takes ownership of the moved graph.

Note
Thread-safe.
Template Parameters
PredicatePredicate type
CCallable type
Parameters
graphTask graph to execute (moved)
predicateBoolean predicate to determine when to stop
callableCallback to invoke after execution completes
Returns
Future that completes when predicate returns true and callback finishes

Definition at line 211 of file executor.hpp.

211 {
212 return Future<void>(executor_.run_until(std::move(std::move(graph).UnderlyingTaskflow()),
213 std::forward<Predicate>(predicate), std::forward<C>(callable)));
214 }

◆ RunUntil() [3/4]

template<std::predicate Predicate>
auto helios::async::Executor::RunUntil ( TaskGraph graph,
Predicate &&  predicate 
) -> Future<void>
inline

Runs a task graph repeatedly until the predicate returns true.

The executor does not own the graph - ensure it remains alive during execution.

Note
Thread-safe.
Template Parameters
PredicatePredicate type
Parameters
graphTask graph to execute
predicateBoolean predicate to determine when to stop
Returns
Future that completes when predicate returns true

Definition at line 163 of file executor.hpp.

163 {
164 return Future<void>(executor_.run_until(graph.UnderlyingTaskflow(), std::forward<Predicate>(predicate)));
165 }

◆ RunUntil() [4/4]

template<std::predicate Predicate, std::invocable C>
auto helios::async::Executor::RunUntil ( TaskGraph graph,
Predicate &&  predicate,
C &&  callable 
) -> Future<void>
inline

Runs a task graph repeatedly until the predicate returns true, then invokes a callback.

The executor does not own the graph - ensure it remains alive during execution.

Note
Thread-safe.
Template Parameters
PredicatePredicate type
CCallable type
Parameters
graphTask graph to execute
predicateBoolean predicate to determine when to stop
callableCallback to invoke after execution completes
Returns
Future that completes when predicate returns true and callback finishes

Definition at line 194 of file executor.hpp.

194 {
195 return Future<void>(
196 executor_.run_until(graph.UnderlyingTaskflow(), std::forward<Predicate>(predicate), std::forward<C>(callable)));
197 }

◆ SilentAsync() [1/2]

template<std::invocable C>
void helios::async::Executor::SilentAsync ( C &&  callable)
inline

Creates an asynchronous task without returning a future.

More efficient than Async when you don't need the result.

Note
Thread-safe.
Template Parameters
CCallable type
Parameters
callableFunction to execute asynchronously

Definition at line 249 of file executor.hpp.

249 {
250 executor_.silent_async(std::forward<C>(callable));
251 }

◆ SilentAsync() [2/2]

template<std::invocable C>
void helios::async::Executor::SilentAsync ( std::string  name,
C &&  callable 
)
inline

Creates a named asynchronous task without returning a future.

More efficient than Async when you don't need the result.

Note
Thread-safe.
Template Parameters
CCallable type
Parameters
nameName for the task (useful for debugging/profiling)
callableFunction to execute asynchronously

Definition at line 372 of file executor.hpp.

372 {
373 tf::TaskParams params;
374 params.name = std::move(name);
375 executor_.silent_async(params, std::forward<C>(callable));
376}

◆ SilentDependentAsync()

template<std::invocable C, std::ranges::range Dependencies>
requires std::same_as<std::ranges::range_value_t<Dependencies>, AsyncTask>
AsyncTask helios::async::Executor::SilentDependentAsync ( C &&  callable,
const Dependencies &  dependencies 
)
inline

Creates an asynchronous task that runs after dependencies complete, without returning a future.

More efficient than DependentAsync when you don't need the result.

Note
Thread-safe.
Template Parameters
CCallable type
DependenciesRange type containing AsyncTask dependencies
Parameters
callableFunction to execute asynchronously
dependenciesTasks that must complete before this task runs
Returns
AsyncTask handle

Definition at line 397 of file executor.hpp.

397 {
398 std::vector<tf::AsyncTask> tf_deps;
399 if constexpr (std::ranges::sized_range<Dependencies>) {
400 tf_deps.reserve(std::ranges::size(dependencies));
401 }
402
403 for (const auto& dep : dependencies) {
404 tf_deps.push_back(dep.UnderlyingTask());
405 }
406
407 return AsyncTask(executor_.silent_dependent_async(std::forward<C>(callable), tf_deps.begin(), tf_deps.end()));
408}

◆ WaitForAll()

void helios::async::Executor::WaitForAll ( )
inline

Blocks until all submitted tasks complete.

Waits for all taskflows and async tasks to finish.

Note
Thread-safe.

Definition at line 298 of file executor.hpp.

298{ executor_.wait_for_all(); }

◆ WorkerCount()

size_t helios::async::Executor::WorkerCount ( ) const
inlinenoexcept

Gets the total number of worker threads.

Note
Thread safe.
Returns
Count of worker threads

Definition at line 337 of file executor.hpp.

337{ return executor_.num_workers(); }