tf::Executor
taskflow/core/executor.hpp
class friend class FlowBuilder FlowBuilder FlowBuilder
class friend class Subflow Subflow Subflow
class friend class Runtime Runtime Runtime
const size_t const size_t tf::Executor::_MAX_STEALS _MAX_STEALS
std::mutex std::mutex tf::Executor::_taskflows_mutex _taskflows_mutex
std::vector< std::thread > std::vector<std::thread> tf::Executor::_threads _threads
std::vector< Worker > std::vector<Worker> tf::Executor::_workers _workers
DefaultNotifier DefaultNotifier tf::Executor::_notifier _notifier
Latch Latch tf::Executor::_latch _latch
std::condition_variable std::condition_variable tf::Executor::_topology_cv _topology_cv
std::mutex std::mutex tf::Executor::_topology_mutex _topology_mutex
size_t size_t tf::Executor::_num_topologies _num_topologies {0}
std::atomic< bool > std::atomic<bool> tf::Executor::_done _done {0}
std::list< Taskflow > std::list<Taskflow> tf::Executor::_taskflows _taskflows
Freelist< Node * > Freelist<Node*> tf::Executor::_freelist _freelist
std::unordered_set< std::shared_ptr< ObserverInterface > > std::unordered_set<std::shared_ptr<ObserverInterface> > tf::Executor::_observers _observers
tf::Executor::Executor
(size_t N=std::thread::hardware_concurrency())
Executor
size_t N std::thread::hardware_concurrency()

constructs the executor with `N` worker threads

N

the number of workers (default std::thread::hardware_concurrency)

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.
tf::Executor::~Executor
()
~Executor

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.

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

runs a taskflow once

taskflow

a tf::Taskflow object

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);
    //dosomethingelse
    future.wait();

This member function is thread-safe.

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

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

runs a moved taskflow once

taskflow

a moved tf::Taskflow object

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));
    //dosomethingelse
    future.wait();

This member function is thread-safe.

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

runs a taskflow once and invoke a callback upon completion

taskflow

a tf::Taskflow object

callable

a callable object to be invoked after this run

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";});
    //dosomethingelse
    future.wait();

This member function is thread-safe.

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

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

runs a moved taskflow once and invoke a callback upon completion

taskflow

a moved tf::Taskflow object

callable

a callable object to be invoked after this run

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";}
    );
    //dosomethingelse
    future.wait();

This member function is thread-safe.

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

runs a taskflow for `N` times

taskflow

a tf::Taskflow object

N

number of runs

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);//runtaskflow2times
    //dosomethingelse
    future.wait();

This member function is thread-safe.

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

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

runs a moved taskflow for `N` times

taskflow

a moved tf::Taskflow object

N

number of runs

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//runthemovedtaskflow2times
    );
    //dosomethingelse
    future.wait();

This member function is thread-safe.

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

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

taskflow

a tf::Taskflow

N

number of runs

callable

a callable object to be invoked after this run

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";}//runstaskflow2timesandinvoke
    //thelambdatoprint"done"
    );
    //dosomethingelse
    future.wait();

This member function is thread-safe.

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

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

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

taskflow

a moved tf::Taskflow

N

number of runs

callable

a callable object to be invoked after this run

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_n(
    //runthemovedtaskflow2timesandinvokethelambdatoprint"done"
    std::move(taskflow),2,[](){std::cout<<"done";}
    );
    //dosomethingelse
    future.wait();

This member function is thread-safe.

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

runs a taskflow multiple times until the predicate becomes true

taskflow

a tf::Taskflow

pred

a boolean predicate to return `true` for stop

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_until(
    taskflow,[](){returnrand()%10==0}
    );
    //dosomethingelse
    future.wait();

This member function is thread-safe.

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

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

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

taskflow

a moved tf::Taskflow object

pred

a boolean predicate to return `true` for stop

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_until(
    std::move(taskflow),[](){returnrand()%10==0}
    );
    //dosomethingelse
    future.wait();

This member function is thread-safe.

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

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

taskflow

a tf::Taskflow

pred

a boolean predicate to return `true` for stop

callable

a callable object to be invoked after this run completes

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_until(
    taskflow,[](){returnrand()%10==0},[](){std::cout<<"done";}
    );
    //dosomethingelse
    future.wait();

This member function is thread-safe.

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

typename P
typename C
tf::Future< void > tf::Future<void> tf::Executor::run_until (Taskflow &&taskflow, P &&pred, C &&callable) 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

taskflow

a moved tf::Taskflow

pred

a boolean predicate to return `true` for stop

callable

a callable object to be invoked after this run completes

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_until(
    std::move(taskflow),
    [](){returnrand()%10==0},[](){std::cout<<"done";}
    );
    //dosomethingelse
    future.wait();

This member function is thread-safe.

typename T
void void tf::Executor::corun (T &target) corun T & target

runs a target graph and waits until it completes using an internal worker of this executor

T

target type which has `tf::Graph& T::graph()` defined

target

the target task graph object

The method runs a target graph which has `tf::Graph& T::graph()` defined and waits until the execution completes. Unlike the typical flow of calling `tf::Executor::run` series plus waiting on the result, this method must be called by an internal worker of this executor. The caller worker will participate in the work-stealing loop of the scheduler, thereby avoiding potential deadlock caused by blocked waiting.

    tf::Executorexecutor(2);
    tf::Taskflowtaskflow;
    std::array<tf::Taskflow, 1000>others;

    std::atomic<size_t>counter{0};

    for(size_tn=0;n<1000;n++){
    for(size_ti=0;i<1000;i++){
    others[n].emplace([&](){counter++;});
    }
    taskflow.emplace([&executor,&tf=others[n]](){
    executor.corun(tf);
    //executor.run(tf).wait();<-blockingtheworkerwithoutdoinganything
    //willintroducedeadlock
    });
    }
    executor.run(taskflow).wait();

The method is thread-safe as long as the target is not concurrently ran by two or more threads.

You must call tf::Executor::corun from a worker of the calling executor or an exception will be thrown.

typename P
void void tf::Executor::corun_until (P &&predicate) corun_until P && predicate

keeps running the work-stealing loop until the predicate becomes true

P

predicate type

predicate

a boolean predicate to indicate when to stop the loop

The method keeps the caller worker running in the work-stealing loop until the stop predicate becomes true.

    taskflow.emplace([&](){
    std::future<void>fu=std::async([](){std::sleep(100s);});
    executor.corun_until([](){
    returnfu.wait_for(std::chrono::seconds(0))==future_status::ready;
    });
    });

You must call tf::Executor::corun_until from a worker of the calling executor or an exception will be thrown.

void void tf::Executor::wait_for_all () wait_for_all

waits 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();//waituntiltheabovesubmittedtaskflowsfinish

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

queries the number of worker threads

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

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

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

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();//0or1(taskflowstillrunning)

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

queries the number of running taskflows with moved ownership

    executor.run(std::move(taskflow));
    std::cout<<executor.num_taskflows();//0or1(taskflowstillrunning)

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

queries the id of the caller thread within 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::Executorexecutor(4);//4workersintheexecutor
    executor.this_worker_id();//-1(mainthreadisnotaworker)

    taskflow.emplace([&](){
    std::cout<<executor.this_worker_id();//0,1,2,or3
    });
    executor.run(taskflow);

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

constructs an observer to inspect the activities of worker threads

Observer

observer type derived from tf::ObserverInterface

ArgsT

argument parameter pack

args

arguments to forward to the constructor of the observer

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.

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

removes an observer from the executor

This member function is not thread-safe.

size_t size_t tf::Executor::num_observers () const noexcept num_observers

queries the number of observers

typename P
typename F
auto auto tf::Executor::async (P &&params, F &&func) async P && params F && func

creates a parameterized asynchronous task to run the given function

P

task parameter type

F

callable type

params

task parameters

func

callable object

a std::future that will hold the result of the execution

The method creates a parameterized asynchronous task to run the given function and return a std::future object that eventually will hold the result of the execution.

    std::future<int>future=executor.async("name",[](){
    std::cout<<"createanasynchronoustaskwithanameandreturns1\n";
    return1;
    });
    future.get();

This member function is thread-safe.

typename F
auto auto tf::Executor::async (F &&func) async F && func

runs a given function asynchronously

F

callable type

func

callable object

a std::future that will hold the result of the execution

The method creates an asynchronous task to run the given function and return a std::future object that eventually will hold the result of the return value.

    std::future<int>future=executor.async([](){
    std::cout<<"createanasynchronoustaskandreturns1\n";
    return1;
    });
    future.get();

This member function is thread-safe.

typename P
typename F
void void tf::Executor::silent_async (P &&params, F &&func) silent_async P && params F && func

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

F

callable type

params

task parameters

func

callable object

The method creates a parameterized asynchronous task to run the given function without returning any std::future object. This member function is more efficient than tf::Executor::async and is encouraged to use when applications do not need a std::future to acquire the result or synchronize the execution.

    executor.silent_async("name",[](){
    std::cout<<"createanasynchronoustaskwithanameandnoreturn\n";
    });
    executor.wait_for_all();

This member function is thread-safe.

typename F
void void tf::Executor::silent_async (F &&func) silent_async F && func

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

F

callable type

func

callable object

The method creates an asynchronous task to run the given function without returning any std::future object. This member function is more efficient than tf::Executor::async and is encouraged to use when applications do not need a std::future to acquire the result or synchronize the execution.

    executor.silent_async([](){
    std::cout<<"createanasynchronoustaskwithnoreturn\n";
    });
    executor.wait_for_all();

This member function is thread-safe.

typename F
typename... Tasks Tasks
std::enable_if_t< all_same_v< AsyncTask, std::decay_t< Tasks >... >, void > * nullptr
tf::AsyncTask tf::AsyncTask tf::Executor::silent_dependent_async (F &&func, Tasks &&... tasks) silent_dependent_async F && func Tasks &&... tasks

runs the given function asynchronously when the given dependents finish

F

callable type

Tasks

task types convertible to tf::AsyncTask

func

callable object

tasks

asynchronous tasks on which this execution depends

a tf::AsyncTask handle

This member function is more efficient than tf::Executor::dependent_async and is encouraged to use when you do not want a std::future to acquire the result or synchronize the execution. The example below creates three asynchronous tasks, `A`, `B`, and `C`, in which task `C` runs after task `A` and task `B`.

    tf::AsyncTaskA=executor.silent_dependent_async([](){printf("A\n");});
    tf::AsyncTaskB=executor.silent_dependent_async([](){printf("B\n");});
    executor.silent_dependent_async([](){printf("CrunsafterAandB\n");},A,B);
    executor.wait_for_all();

This member function is thread-safe.

typename P
typename F
typename... Tasks Tasks
std::enable_if_t< is_task_params_v< P > &&all_same_v< AsyncTask, std::decay_t< Tasks >... >, void > * nullptr
tf::AsyncTask tf::AsyncTask tf::Executor::silent_dependent_async (P &&params, F &&func, Tasks &&... tasks) silent_dependent_async P && params F && func Tasks &&... tasks

runs the given function asynchronously when the given dependents finish

F

callable type

Tasks

task types convertible to tf::AsyncTask

params

task parameters

func

callable object

tasks

asynchronous tasks on which this execution depends

a tf::AsyncTask handle

This member function is more efficient than tf::Executor::dependent_async and is encouraged to use when you do not want a std::future to acquire the result or synchronize the execution. The example below creates three asynchronous tasks, `A`, `B`, and `C`, in which task `C` runs after task `A` and task `B`. Assigned task names will appear in the observers of the executor.

    tf::AsyncTaskA=executor.silent_dependent_async("A",[](){printf("A\n");});
    tf::AsyncTaskB=executor.silent_dependent_async("B",[](){printf("B\n");});
    executor.silent_dependent_async(
    "C",[](){printf("CrunsafterAandB\n");},A,B
    );
    executor.wait_for_all();

This member function is thread-safe.

typename F
typename I
std::enable_if_t<!std::is_same_v< std::decay_t< I >, AsyncTask >, void > * nullptr
tf::AsyncTask tf::AsyncTask tf::Executor::silent_dependent_async (F &&func, I first, I last) silent_dependent_async F && func I first I last

runs the given function asynchronously when the given range of dependents finish

F

callable type

I

iterator type

func

callable object

first

iterator to the beginning (inclusive)

last

iterator to the end (exclusive)

a tf::AsyncTask handle

This member function is more efficient than tf::Executor::dependent_async and is encouraged to use when you do not want a std::future to acquire the result or synchronize the execution. The example below creates three asynchronous tasks, `A`, `B`, and `C`, in which task `C` runs after task `A` and task `B`.

    std::array<tf::AsyncTask, 2>array{
    executor.silent_dependent_async([](){printf("A\n");}),
    executor.silent_dependent_async([](){printf("B\n");})
    };
    executor.silent_dependent_async(
    [](){printf("CrunsafterAandB\n");},array.begin(),array.end()
    );
    executor.wait_for_all();

This member function is thread-safe.

typename P
typename F
typename I
std::enable_if_t< is_task_params_v< P > &&!std::is_same_v< std::decay_t< I >, AsyncTask >, void > * nullptr
tf::AsyncTask tf::AsyncTask tf::Executor::silent_dependent_async (P &&params, F &&func, I first, I last) silent_dependent_async P && params F && func I first I last

runs the given function asynchronously when the given range of dependents finish

F

callable type

I

iterator type

params

tasks parameters

func

callable object

first

iterator to the beginning (inclusive)

last

iterator to the end (exclusive)

a tf::AsyncTask handle

This member function is more efficient than tf::Executor::dependent_async and is encouraged to use when you do not want a std::future to acquire the result or synchronize the execution. The example below creates three asynchronous tasks, `A`, `B`, and `C`, in which task `C` runs after task `A` and task `B`. Assigned task names will appear in the observers of the executor.

    std::array<tf::AsyncTask, 2>array{
    executor.silent_dependent_async("A",[](){printf("A\n");}),
    executor.silent_dependent_async("B",[](){printf("B\n");})
    };
    executor.silent_dependent_async(
    "C",[](){printf("CrunsafterAandB\n");},array.begin(),array.end()
    );
    executor.wait_for_all();

This member function is thread-safe.

typename F
typename... Tasks Tasks
std::enable_if_t< all_same_v< AsyncTask, std::decay_t< Tasks >... >, void > * nullptr
auto auto tf::Executor::dependent_async (F &&func, Tasks &&... tasks) dependent_async F && func Tasks &&... tasks

runs the given function asynchronously when the given dependents finish

F

callable type

Tasks

task types convertible to tf::AsyncTask

func

callable object

tasks

asynchronous tasks on which this execution depends

a pair of a tf::AsyncTask handle and a std::future that holds the result of the execution

The example below creates three asynchronous tasks, `A`, `B`, and `C`, in which task `C` runs after task `A` and task `B`. Task `C` returns a pair of its tf::AsyncTask handle and a std::future<int> that eventually will hold the result of the execution.

    tf::AsyncTaskA=executor.silent_dependent_async([](){printf("A\n");});
    tf::AsyncTaskB=executor.silent_dependent_async([](){printf("B\n");});
    auto[C,fuC]=executor.dependent_async(
    [](){
    printf("CrunsafterAandB\n");
    return1;
    },
    A,B
    );
    fuC.get();//Cfinishes,whichinturnsmeansbothAandBfinish

You can mixed the use of tf::AsyncTask handles returned by Executor::dependent_async and Executor::silent_dependent_async when specifying task dependencies.

This member function is thread-safe.

typename P
typename F
typename... Tasks Tasks
std::enable_if_t< is_task_params_v< P > &&all_same_v< AsyncTask, std::decay_t< Tasks >... >, void > * nullptr
auto auto tf::Executor::dependent_async (P &&params, F &&func, Tasks &&... tasks) dependent_async P && params F && func Tasks &&... tasks

runs the given function asynchronously when the given dependents finish

P

task parameters type

F

callable type

Tasks

task types convertible to tf::AsyncTask

params

task parameters

func

callable object

tasks

asynchronous tasks on which this execution depends

a pair of a tf::AsyncTask handle and a std::future that holds the result of the execution

The example below creates three named asynchronous tasks, `A`, `B`, and `C`, in which task `C` runs after task `A` and task `B`. Task `C` returns a pair of its tf::AsyncTask handle and a std::future<int> that eventually will hold the result of the execution. Assigned task names will appear in the observers of the executor.

    tf::AsyncTaskA=executor.silent_dependent_async("A",[](){printf("A\n");});
    tf::AsyncTaskB=executor.silent_dependent_async("B",[](){printf("B\n");});
    auto[C,fuC]=executor.dependent_async(
    "C",
    [](){
    printf("CrunsafterAandB\n");
    return1;
    },
    A,B
    );
    assert(fuC.get()==1);//Cfinishes,whichinturnsmeansbothAandBfinish

You can mixed the use of tf::AsyncTask handles returned by Executor::dependent_async and Executor::silent_dependent_async when specifying task dependencies.

This member function is thread-safe.

typename F
typename I
std::enable_if_t<!std::is_same_v< std::decay_t< I >, AsyncTask >, void > * nullptr
auto auto tf::Executor::dependent_async (F &&func, I first, I last) dependent_async F && func I first I last

runs the given function asynchronously when the given range of dependents finish

F

callable type

I

iterator type

func

callable object

first

iterator to the beginning (inclusive)

last

iterator to the end (exclusive)

a pair of a tf::AsyncTask handle and a std::future that holds the result of the execution

The example below creates three asynchronous tasks, `A`, `B`, and `C`, in which task `C` runs after task `A` and task `B`. Task `C` returns a pair of its tf::AsyncTask handle and a std::future<int> that eventually will hold the result of the execution.

    std::array<tf::AsyncTask, 2>array{
    executor.silent_dependent_async([](){printf("A\n");}),
    executor.silent_dependent_async([](){printf("B\n");})
    };
    auto[C,fuC]=executor.dependent_async(
    [](){
    printf("CrunsafterAandB\n");
    return1;
    },
    array.begin(),array.end()
    );
    assert(fuC.get()==1);//Cfinishes,whichinturnsmeansbothAandBfinish

You can mixed the use of tf::AsyncTask handles returned by Executor::dependent_async and Executor::silent_dependent_async when specifying task dependencies.

This member function is thread-safe.

typename P
typename F
typename I
std::enable_if_t< is_task_params_v< P > &&!std::is_same_v< std::decay_t< I >, AsyncTask >, void > * nullptr
auto auto tf::Executor::dependent_async (P &&params, F &&func, I first, I last) dependent_async P && params F && func I first I last

runs the given function asynchronously when the given range of dependents finish

P

task parameters type

F

callable type

I

iterator type

params

task parameters

func

callable object

first

iterator to the beginning (inclusive)

last

iterator to the end (exclusive)

a pair of a tf::AsyncTask handle and a std::future that holds the result of the execution

The example below creates three named asynchronous tasks, `A`, `B`, and `C`, in which task `C` runs after task `A` and task `B`. Task `C` returns a pair of its tf::AsyncTask handle and a std::future<int> that eventually will hold the result of the execution. Assigned task names will appear in the observers of the executor.

    std::array<tf::AsyncTask, 2>array{
    executor.silent_dependent_async("A",[](){printf("A\n");}),
    executor.silent_dependent_async("B",[](){printf("B\n");})
    };
    auto[C,fuC]=executor.dependent_async(
    "C",
    [](){
    printf("CrunsafterAandB\n");
    return1;
    },
    array.begin(),array.end()
    );
    assert(fuC.get()==1);//Cfinishes,whichinturnsmeansbothAandBfinish

You can mixed the use of tf::AsyncTask handles returned by Executor::dependent_async and Executor::silent_dependent_async when specifying task dependencies.

This member function is thread-safe.

bool bool tf::Executor::_wait_for_task (Worker &, Node *&) _wait_for_task Worker & Node *&
bool bool tf::Executor::_invoke_module_task_internal (Worker &, Node *) _invoke_module_task_internal Worker & Node *
void void tf::Executor::_observer_prologue (Worker &, Node *) _observer_prologue Worker & Node *
void void tf::Executor::_observer_epilogue (Worker &, Node *) _observer_epilogue Worker & Node *
void void tf::Executor::_spawn (size_t) _spawn size_t
void void tf::Executor::_exploit_task (Worker &, Node *&) _exploit_task Worker & Node *&
void void tf::Executor::_explore_task (Worker &, Node *&) _explore_task Worker & Node *&
void void tf::Executor::_schedule (Worker &, Node *) _schedule Worker & Node *
void void tf::Executor::_schedule (Node *) _schedule Node *
void void tf::Executor::_schedule (Worker &, const SmallVector< Node * > &) _schedule Worker & const SmallVector< Node * > &
void void tf::Executor::_schedule (const SmallVector< Node * > &) _schedule const SmallVector< Node * > &
void void tf::Executor::_set_up_topology (Worker *, Topology *) _set_up_topology Worker * Topology *
void void tf::Executor::_set_up_graph (Graph &, Node *, Topology *, int, SmallVector< Node * > &) _set_up_graph Graph & Node * Topology * int SmallVector< Node * > &
void void tf::Executor::_tear_down_topology (Worker &, Topology *) _tear_down_topology Worker & Topology *
void void tf::Executor::_tear_down_async (Node *) _tear_down_async Node *
void void tf::Executor::_tear_down_dependent_async (Worker &, Node *) _tear_down_dependent_async Worker & Node *
void void tf::Executor::_tear_down_invoke (Worker &, Node *) _tear_down_invoke Worker & Node *
void void tf::Executor::_increment_topology () _increment_topology
void void tf::Executor::_decrement_topology () _decrement_topology
void void tf::Executor::_invoke (Worker &, Node *) _invoke Worker & Node *
void void tf::Executor::_invoke_static_task (Worker &, Node *) _invoke_static_task Worker & Node *
void void tf::Executor::_invoke_subflow_task (Worker &, Node *) _invoke_subflow_task Worker & Node *
void void tf::Executor::_detach_subflow_task (Worker &, Node *, Graph &) _detach_subflow_task Worker & Node * Graph &
void void tf::Executor::_invoke_condition_task (Worker &, Node *, SmallVector< int > &) _invoke_condition_task Worker & Node * SmallVector< int > &
void void tf::Executor::_invoke_multi_condition_task (Worker &, Node *, SmallVector< int > &) _invoke_multi_condition_task Worker & Node * SmallVector< int > &
void void tf::Executor::_invoke_module_task (Worker &, Node *) _invoke_module_task Worker & Node *
void void tf::Executor::_invoke_async_task (Worker &, Node *) _invoke_async_task Worker & Node *
void void tf::Executor::_invoke_dependent_async_task (Worker &, Node *) _invoke_dependent_async_task Worker & Node *
void void tf::Executor::_process_async_dependent (Node *, tf::AsyncTask &, size_t &) _process_async_dependent Node * tf::AsyncTask & size_t &
void void tf::Executor::_process_exception (Worker &, Node *) _process_exception Worker & Node *
void void tf::Executor::_schedule_async_task (Node *) _schedule_async_task Node *
void void tf::Executor::_corun_graph (Worker &, Node *, Graph &) _corun_graph Worker & Node * Graph &
typename P
void void tf::Executor::_corun_until (Worker &, P &&) _corun_until Worker & P &&

class to create an executor

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

    //Declareanexecutorandataskflow
    tf::Executorexecutor;
    tf::Taskflowtaskflow;

    //Addthreetasksintothetaskflow
    tf::TaskA=taskflow.emplace([](){std::cout<<"ThisisTaskA\n";});
    tf::TaskB=taskflow.emplace([](){std::cout<<"ThisisTaskB\n";});
    tf::TaskC=taskflow.emplace([](){std::cout<<"ThisisTaskC\n";});

    //Buildprecedencebetweentasks
    A.precede(B,C);

    tf::Future<void>fu=executor.run(taskflow);
    fu.wait();//blockuntiltheexecutioncompletes

    executor.run(taskflow,[](){std::cout<<"endof1run";}).wait();
    executor.run_n(taskflow,4);
    executor.wait_for_all();//blockuntilallassociatedexecutionsfinish
    executor.run_n(taskflow,4,[](){std::cout<<"endof4runs";}).wait();
    executor.run_until(taskflow,[cnt=0]()mutable{return++cnt==10;});

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

- tf::Executor
  _corun_graph
- tf::Executor
  _corun_until
- tf::Executor
  _decrement_topology
- tf::Executor
  _detach_subflow_task
- tf::Executor
  _done
- tf::Executor
  _exploit_task
- tf::Executor
  _explore_task
- tf::Executor
  _freelist
- tf::Executor
  _increment_topology
- tf::Executor
  _invoke
- tf::Executor
  _invoke_async_task
- tf::Executor
  _invoke_condition_task
- tf::Executor
  _invoke_dependent_async_task
- tf::Executor
  _invoke_module_task
- tf::Executor
  _invoke_module_task_internal
- tf::Executor
  _invoke_multi_condition_task
- tf::Executor
  _invoke_static_task
- tf::Executor
  _invoke_subflow_task
- tf::Executor
  _latch
- tf::Executor
  _MAX_STEALS
- tf::Executor
  _notifier
- tf::Executor
  _num_topologies
- tf::Executor
  _observer_epilogue
- tf::Executor
  _observer_prologue
- tf::Executor
  _observers
- tf::Executor
  _process_async_dependent
- tf::Executor
  _process_exception
- tf::Executor
  _schedule
- tf::Executor
  _schedule
- tf::Executor
  _schedule
- tf::Executor
  _schedule
- tf::Executor
  _schedule_async_task
- tf::Executor
  _set_up_graph
- tf::Executor
  _set_up_topology
- tf::Executor
  _spawn
- tf::Executor
  _taskflows
- tf::Executor
  _taskflows_mutex
- tf::Executor
  _tear_down_async
- tf::Executor
  _tear_down_dependent_async
- tf::Executor
  _tear_down_invoke
- tf::Executor
  _tear_down_topology
- tf::Executor
  _threads
- tf::Executor
  _topology_cv
- tf::Executor
  _topology_mutex
- tf::Executor
  _wait_for_task
- tf::Executor
  _workers
- tf::Executor
  async
- tf::Executor
  async
- tf::Executor
  corun
- tf::Executor
  corun_until
- tf::Executor
  dependent_async
- tf::Executor
  dependent_async
- tf::Executor
  dependent_async
- tf::Executor
  dependent_async
- tf::Executor
  Executor
- tf::Executor
  FlowBuilder
- tf::Executor
  make_observer
- tf::Executor
  num_observers
- tf::Executor
  num_taskflows
- tf::Executor
  num_topologies
- tf::Executor
  num_workers
- tf::Executor
  remove_observer
- tf::Executor
  run
- tf::Executor
  run
- tf::Executor
  run
- tf::Executor
  run
- tf::Executor
  run_n
- tf::Executor
  run_n
- tf::Executor
  run_n
- tf::Executor
  run_n
- tf::Executor
  run_until
- tf::Executor
  run_until
- tf::Executor
  run_until
- tf::Executor
  run_until
- tf::Executor
  Runtime
- tf::Executor
  silent_async
- tf::Executor
  silent_async
- tf::Executor
  silent_dependent_async
- tf::Executor
  silent_dependent_async
- tf::Executor
  silent_dependent_async
- tf::Executor
  silent_dependent_async
- tf::Executor
  Subflow
- tf::Executor
  this_worker_id
- tf::Executor
  wait_for_all
- tf::Executor
  ~Executor