Taskflow  3.2.0-Master-Branch
Loading...
Searching...
No Matches
tf::Executor Class Reference

class to create an executor for running a taskflow graph More...

#include <executor.hpp>

Public Member Functions

 Executor (size_t N=std::thread::hardware_concurrency())
 constructs the executor with N worker threads
 
 ~Executor ()
 destructs the executor
 
tf::Future< void > run (Taskflow &taskflow)
 runs a taskflow once
 
tf::Future< void > run (Taskflow &&taskflow)
 runs a moved taskflow once
 
template<typename C >
tf::Future< void > run (Taskflow &taskflow, C &&callable)
 runs a taskflow once and invoke a callback upon completion
 
template<typename C >
tf::Future< void > run (Taskflow &&taskflow, C &&callable)
 runs a moved taskflow once and invoke a callback upon completion
 
tf::Future< void > run_n (Taskflow &taskflow, size_t N)
 runs a taskflow for N times
 
tf::Future< void > run_n (Taskflow &&taskflow, size_t N)
 runs a moved taskflow for N times
 
template<typename C >
tf::Future< void > run_n (Taskflow &taskflow, size_t N, C &&callable)
 runs a taskflow for N times and then invokes a callback
 
template<typename C >
tf::Future< void > run_n (Taskflow &&taskflow, size_t N, C &&callable)
 runs a moved taskflow for N times and then invokes a callback
 
template<typename P >
tf::Future< void > run_until (Taskflow &taskflow, P &&pred)
 runs a taskflow multiple times until the predicate becomes true
 
template<typename P >
tf::Future< void > run_until (Taskflow &&taskflow, P &&pred)
 runs a moved taskflow and keeps running it until the predicate becomes true
 
template<typename P , typename C >
tf::Future< void > run_until (Taskflow &taskflow, P &&pred, C &&callable)
 runs a taskflow multiple times until the predicate becomes true and then invokes the callback
 
template<typename P , typename C >
tf::Future< void > run_until (Taskflow &&taskflow, P &&pred, C &&callable)
 runs a moved taskflow and keeps running it until the predicate becomes true and then invokes the callback
 
void wait_for_all ()
 wait for all tasks to complete
 
size_t num_workers () const noexcept
 queries the number of worker threads
 
size_t num_topologies () const
 queries the number of running topologies at the time of this call
 
size_t num_taskflows () const
 queries the number of running taskflows with moved ownership
 
int this_worker_id () const
 queries the id of the caller thread in this executor
 
template<typename F , typename... ArgsT>
auto async (F &&f, ArgsT &&... args)
 runs a given function asynchronously
 
template<typename F , typename... ArgsT>
auto named_async (const std::string &name, F &&f, ArgsT &&... args)
 runs a given function asynchronously and gives a name to this task
 
template<typename F , typename... ArgsT>
void silent_async (F &&f, ArgsT &&... args)
 similar to tf::Executor::async but does not return a future object
 
template<typename F , typename... ArgsT>
void named_silent_async (const std::string &name, F &&f, ArgsT &&... args)
 similar to tf::Executor::named_async but does not return a future object
 
template<typename Observer , typename... ArgsT>
std::shared_ptr< Observer > make_observer (ArgsT &&... args)
 constructs an observer to inspect the activities of worker threads
 
template<typename Observer >
void remove_observer (std::shared_ptr< Observer > observer)
 removes an observer from the executor
 
size_t num_observers () const noexcept
 queries the number of observers
 

Friends

class FlowBuilder
 
class Subflow
 
class Runtime
 

Detailed Description

class to create an executor for running a taskflow graph

An executor manages a set of worker threads to run one or multiple taskflows using an efficient work-stealing scheduling algorithm.

// Declare an executor and a taskflow
tf::Executor executor;
tf::Taskflow taskflow;
// Add three tasks into the taskflow
tf::Task A = taskflow.emplace([] () { std::cout << "This is TaskA\n"; });
tf::Task B = taskflow.emplace([] () { std::cout << "This is TaskB\n"; });
tf::Task C = taskflow.emplace([] () { std::cout << "This is TaskC\n"; });
// Build precedence between tasks
A.precede(B, C);
tf::Future<void> fu = executor.run(taskflow);
fu.wait(); // block until the execution completes
executor.run(taskflow, [](){ std::cout << "end of 1 run"; }).wait();
executor.run_n(taskflow, 4);
executor.wait_for_all(); // block until all associated executions finish
executor.run_n(taskflow, 4, [](){ std::cout << "end of 4 runs"; }).wait();
executor.run_until(taskflow, [cnt=0] () mutable { return ++cnt == 10; });
class to create an executor for running a taskflow graph
Definition executor.hpp:50
tf::Future< void > run_until(Taskflow &taskflow, P &&pred)
runs a taskflow multiple times until the predicate becomes true
Definition executor.hpp:1622
tf::Future< void > run(Taskflow &taskflow)
runs a taskflow once
Definition executor.hpp:1573
tf::Future< void > run_n(Taskflow &taskflow, size_t N)
runs a taskflow for N times
Definition executor.hpp:1595
void wait_for_all()
wait for all tasks to complete
Definition executor.hpp:1709
Task emplace(C &&callable)
creates a static task
Definition flow_builder.hpp:742
class to access the result of an execution
Definition core/taskflow.hpp:571
class to create a task handle over a node in a taskflow graph
Definition task.hpp:187
Task & precede(Ts &&... tasks)
adds precedence links from this to other tasks
Definition task.hpp:420
class to create a taskflow object
Definition core/taskflow.hpp:73

All the run methods are thread-safe. You can submit multiple taskflows at the same time to an executor from different threads.

Constructor & Destructor Documentation

◆ Executor()

tf::Executor::Executor ( size_t  N = std::thread::hardware_concurrency())
inlineexplicit

constructs the executor with N worker threads

The constructor spawns N worker threads to run tasks in a work-stealing loop. The number of workers must be greater than zero or an exception will be thrown. By default, the number of worker threads is equal to the maximum hardware concurrency returned by std::thread::hardware_concurrency.

◆ ~Executor()

tf::Executor::~Executor ( )
inline

destructs the executor

The destructor calls Executor::wait_for_all to wait for all submitted taskflows to complete and then notifies all worker threads to stop and join these threads.

Member Function Documentation

◆ async()

template<typename F , typename... ArgsT>
auto tf::Executor::async ( F &&  f,
ArgsT &&...  args 
)

runs a given function asynchronously

Template Parameters
Fcallable type
ArgsTparameter types
Parameters
fcallable object to call
argsparameters to pass to the callable
Returns
a tf::Future that will holds the result of the execution

The method creates an asynchronous task to launch the given function on the given arguments. Unlike std::async, the return here is a tf::Future that holds an optional object to the result. If the asynchronous task is cancelled before it runs, the return is a std::nullopt, or the value returned by the callable.

tf::Fugure<std::optional<int>> future = executor.async([](){
std::cout << "create an asynchronous task and returns 1\n";
return 1;
});

This member function is thread-safe.

◆ make_observer()

template<typename Observer , typename... ArgsT>
std::shared_ptr< Observer > tf::Executor::make_observer ( ArgsT &&...  args)

constructs an observer to inspect the activities of worker threads

Template Parameters
Observerobserver type derived from tf::ObserverInterface
ArgsTargument parameter pack
Parameters
argsarguments to forward to the constructor of the observer
Returns
a shared pointer to the created observer

Each executor manages a list of observers with shared ownership with callers. For each of these observers, the two member functions, tf::ObserverInterface::on_entry and tf::ObserverInterface::on_exit will be called before and after the execution of a task.

This member function is not thread-safe.

◆ named_async()

template<typename F , typename... ArgsT>
auto tf::Executor::named_async ( const std::string name,
F &&  f,
ArgsT &&...  args 
)

runs a given function asynchronously and gives a name to this task

Template Parameters
Fcallable type
ArgsTparameter types
Parameters
namename of the asynchronous task
fcallable object to call
argsparameters to pass to the callable
Returns
a tf::Future that will holds the result of the execution

The method creates a named asynchronous task to launch the given function on the given arguments. Naming an asynchronous task is primarily used for profiling and visualizing the task execution timeline. Unlike std::async, the return here is a tf::Future that holds an optional object to the result. If the asynchronous task is cancelled before it runs, the return is a std::nullopt, or the value returned by the callable.

tf::Fugure<std::optional<int>> future = executor.named_async("name", [](){
std::cout << "create an asynchronous task with a name and returns 1\n";
return 1;
});

This member function is thread-safe.

◆ named_silent_async()

template<typename F , typename... ArgsT>
void tf::Executor::named_silent_async ( const std::string name,
F &&  f,
ArgsT &&...  args 
)

similar to tf::Executor::named_async but does not return a future object

This member function is more efficient than tf::Executor::named_async and is encouraged to use when there is no data returned.

executor.named_silent_async("name", [](){
std::cout << "create an asynchronous task with a name and no return\n";
});

This member function is thread-safe.

◆ num_taskflows()

size_t tf::Executor::num_taskflows ( ) const
inline

queries the number of running taskflows with moved ownership

executor.run(std::move(taskflow));
std::cout << executor.num_taskflows(); // 0 or 1 (taskflow still running)
T move(T... args)

◆ num_topologies()

size_t tf::Executor::num_topologies ( ) const
inline

queries the number of running topologies at the time of this call

When a taskflow is submitted to an executor, a topology is created to store runtime metadata of the running taskflow. When the execution of the submitted taskflow finishes, its corresponding topology will be removed from the executor.

executor.run(taskflow);
std::cout << executor.num_topologies(); // 0 or 1 (taskflow still running)

◆ num_workers()

size_t tf::Executor::num_workers ( ) const
inlinenoexcept

queries the number of worker threads

Each worker represents one unique thread spawned by an executor upon its construction time.

tf::Executor executor(4);
std::cout << executor.num_workers(); // 4

◆ remove_observer()

template<typename Observer >
void tf::Executor::remove_observer ( std::shared_ptr< Observer >  observer)

removes an observer from the executor

This member function is not thread-safe.

◆ run() [1/4]

tf::Future< void > tf::Executor::run ( Taskflow &&  taskflow)
inline

runs a moved taskflow once

Parameters
taskflowa moved tf::Taskflow object
Returns
a tf::Future that holds the result of the execution

This member function executes a moved taskflow once and returns a tf::Future object that eventually holds the result of the execution. The executor will take care of the lifetime of the moved taskflow.

tf::Future<void> future = executor.run(std::move(taskflow));
// do something else
future.wait();

This member function is thread-safe.

◆ run() [2/4]

template<typename C >
tf::Future< void > tf::Executor::run ( Taskflow &&  taskflow,
C &&  callable 
)

runs a moved taskflow once and invoke a callback upon completion

Parameters
taskflowa moved tf::Taskflow object
callablea callable object to be invoked after this run
Returns
a tf::Future that holds the result of the execution

This member function executes a moved taskflow once and invokes the given callable when the execution completes. This member function returns a tf::Future object that eventually holds the result of the execution. The executor will take care of the lifetime of the moved taskflow.

tf::Future<void> future = executor.run(
std::move(taskflow), [](){ std::cout << "done"; }
);
// do something else
future.wait();

This member function is thread-safe.

◆ run() [3/4]

tf::Future< void > tf::Executor::run ( Taskflow taskflow)
inline

runs a taskflow once

Parameters
taskflowa tf::Taskflow object
Returns
a tf::Future that holds the result of the execution

This member function executes the given taskflow once and returns a tf::Future object that eventually holds the result of the execution.

tf::Future<void> future = executor.run(taskflow);
// do something else
future.wait();

This member function is thread-safe.

Attention
The executor does not own the given taskflow. It is your responsibility to ensure the taskflow remains alive during its execution.

◆ run() [4/4]

template<typename C >
tf::Future< void > tf::Executor::run ( Taskflow taskflow,
C &&  callable 
)

runs a taskflow once and invoke a callback upon completion

Parameters
taskflowa tf::Taskflow object
callablea callable object to be invoked after this run
Returns
a tf::Future that holds the result of the execution

This member function executes the given taskflow once and invokes the given callable when the execution completes. This member function returns a tf::Future object that eventually holds the result of the execution.

tf::Future<void> future = executor.run(taskflow, [](){ std::cout << "done"; });
// do something else
future.wait();

This member function is thread-safe.

Attention
The executor does not own the given taskflow. It is your responsibility to ensure the taskflow remains alive during its execution.

◆ run_n() [1/4]

tf::Future< void > tf::Executor::run_n ( Taskflow &&  taskflow,
size_t  N 
)
inline

runs a moved taskflow for N times

Parameters
taskflowa moved tf::Taskflow object
Nnumber of runs
Returns
a tf::Future that holds the result of the execution

This member function executes a moved taskflow N times and returns a tf::Future object that eventually holds the result of the execution. The executor will take care of the lifetime of the moved taskflow.

tf::Future<void> future = executor.run_n(
std::move(taskflow), 2 // run the moved taskflow 2 times
);
// do something else
future.wait();

This member function is thread-safe.

◆ run_n() [2/4]

template<typename C >
tf::Future< void > tf::Executor::run_n ( Taskflow &&  taskflow,
size_t  N,
C &&  callable 
)

runs a moved taskflow for N times and then invokes a callback

Parameters
taskflowa moved tf::Taskflow
Nnumber of runs
callablea callable object to be invoked after this run
Returns
a tf::Future that holds the result of the execution

This member function executes a moved taskflow N times and invokes the given callable when the execution completes. This member function returns a tf::Future object that eventually holds the result of the execution.

tf::Future<void> future = executor.run(
// run the moved taskflow 2 times and invoke the lambda to print "done"
std::move(taskflow), 2, [](){ std::cout << "done"; }
);
// do something else
future.wait();

This member function is thread-safe.

◆ run_n() [3/4]

tf::Future< void > tf::Executor::run_n ( Taskflow taskflow,
size_t  N 
)
inline

runs a taskflow for N times

Parameters
taskflowa tf::Taskflow object
Nnumber of runs
Returns
a tf::Future that holds the result of the execution

This member function executes the given taskflow N times and returns a tf::Future object that eventually holds the result of the execution.

tf::Future<void> future = executor.run_n(taskflow, 2); // run taskflow 2 times
// do something else
future.wait();

This member function is thread-safe.

Attention
The executor does not own the given taskflow. It is your responsibility to ensure the taskflow remains alive during its execution.

◆ run_n() [4/4]

template<typename C >
tf::Future< void > tf::Executor::run_n ( Taskflow taskflow,
size_t  N,
C &&  callable 
)

runs a taskflow for N times and then invokes a callback

Parameters
taskflowa tf::Taskflow
Nnumber of runs
callablea callable object to be invoked after this run
Returns
a tf::Future that holds the result of the execution

This member function executes the given taskflow N times and invokes the given callable when the execution completes. This member function returns a tf::Future object that eventually holds the result of the execution.

tf::Future<void> future = executor.run(
taskflow, 2, [](){ std::cout << "done"; } // runs taskflow 2 times and invoke
// the lambda to print "done"
);
// do something else
future.wait();

This member function is thread-safe.

Attention
The executor does not own the given taskflow. It is your responsibility to ensure the taskflow remains alive during its execution.

◆ run_until() [1/4]

template<typename P >
tf::Future< void > tf::Executor::run_until ( Taskflow &&  taskflow,
P &&  pred 
)

runs a moved taskflow and keeps running it until the predicate becomes true

Parameters
taskflowa moved tf::Taskflow object
preda boolean predicate to return true for stop
Returns
a tf::Future that holds the result of the execution

This member function executes a moved taskflow multiple times until the predicate returns true. This member function returns a tf::Future object that eventually holds the result of the execution. The executor will take care of the lifetime of the moved taskflow.

tf::Future<void> future = executor.run(
std::move(taskflow), [](){ return rand()%10 == 0 }
);
// do something else
future.wait();

This member function is thread-safe.

◆ run_until() [2/4]

template<typename P , typename C >
tf::Future< void > tf::Executor::run_until ( Taskflow &&  taskflow,
P &&  pred,
C &&  callable 
)

runs a moved taskflow and keeps running it until the predicate becomes true and then invokes the callback

Parameters
taskflowa moved tf::Taskflow
preda boolean predicate to return true for stop
callablea callable object to be invoked after this run completes
Returns
a tf::Future that holds the result of the execution

This member function executes a moved taskflow multiple times until the predicate returns true and then invokes the given callable when the execution completes. This member function returns a tf::Future object that eventually holds the result of the execution. The executor will take care of the lifetime of the moved taskflow.

tf::Future<void> future = executor.run(
std::move(taskflow),
[](){ return rand()%10 == 0 }, [](){ std::cout << "done"; }
);
// do something else
future.wait();

This member function is thread-safe.

◆ run_until() [3/4]

template<typename P >
tf::Future< void > tf::Executor::run_until ( Taskflow taskflow,
P &&  pred 
)

runs a taskflow multiple times until the predicate becomes true

Parameters
taskflowa tf::Taskflow
preda boolean predicate to return true for stop
Returns
a tf::Future that holds the result of the execution

This member function executes the given taskflow multiple times until the predicate returns true. This member function returns a tf::Future object that eventually holds the result of the execution.

tf::Future<void> future = executor.run(
taskflow, [](){ return rand()%10 == 0 }
);
// do something else
future.wait();

This member function is thread-safe.

Attention
The executor does not own the given taskflow. It is your responsibility to ensure the taskflow remains alive during its execution.

◆ run_until() [4/4]

template<typename P , typename C >
tf::Future< void > tf::Executor::run_until ( Taskflow taskflow,
P &&  pred,
C &&  callable 
)

runs a taskflow multiple times until the predicate becomes true and then invokes the callback

Parameters
taskflowa tf::Taskflow
preda boolean predicate to return true for stop
callablea callable object to be invoked after this run completes
Returns
a tf::Future that holds the result of the execution

This member function executes the given taskflow multiple times until the predicate returns true and then invokes the given callable when the execution completes. This member function returns a tf::Future object that eventually holds the result of the execution.

tf::Future<void> future = executor.run(
taskflow, [](){ return rand()%10 == 0 }, [](){ std::cout << "done"; }
);
// do something else
future.wait();

This member function is thread-safe.

Attention
The executor does not own the given taskflow. It is your responsibility to ensure the taskflow remains alive during its execution.

◆ silent_async()

template<typename F , typename... ArgsT>
void tf::Executor::silent_async ( F &&  f,
ArgsT &&...  args 
)

similar to tf::Executor::async but does not return a future object

This member function is more efficient than tf::Executor::async and is encouraged to use when there is no data returned.

executor.silent_async([](){
std::cout << "create an asynchronous task with no return\n";
});

This member function is thread-safe.

◆ this_worker_id()

int tf::Executor::this_worker_id ( ) const
inline

queries the id of the caller thread in this executor

Each worker has an unique id in the range of 0 to N-1 associated with its parent executor. If the caller thread does not belong to the executor, -1 is returned.

tf::Executor executor(4); // 4 workers in the executor
executor.this_worker_id(); // -1 (main thread is not a worker)
taskflow.emplace([&](){
std::cout << executor.this_worker_id(); // 0, 1, 2, or 3
});
executor.run(taskflow);

◆ wait_for_all()

void tf::Executor::wait_for_all ( )
inline

wait for all tasks to complete

This member function waits until all submitted tasks (e.g., taskflows, asynchronous tasks) to finish.

executor.run(taskflow1);
executor.run_n(taskflow2, 10);
executor.run_n(taskflow3, 100);
executor.wait_for_all(); // wait until the above submitted taskflows finish

The documentation for this class was generated from the following files: