docs/classtf_1_1Taskflow.html
class to create a taskflow object
A taskflow manages a task dependency graph where each task represents a callable object (e.g., lambda, std::function) and an edge represents a dependency between two tasks. A task is one of the following types:
std::function<void()>std::function<void(tf::Subflow&)>std::function<int()>std::function<tf::SmallVector<int>()>std::function<void(tf::Runtime&)>Each task is a basic computation unit and is run by one worker thread from an executor. The following example creates a simple taskflow graph of four static tasks, A, B, C, and D, where A runs before B and C and D runs after B and C.
tf::Executor executor;tf::Taskflow taskflow("simple");tf::Task A = taskflow.emplace([](){ std::cout \<\< "TaskA\n"; });tf::Task B = taskflow.emplace([](){ std::cout \<\< "TaskB\n"; });tf::Task C = taskflow.emplace([](){ std::cout \<\< "TaskC\n"; });tf::Task D = taskflow.emplace([](){ std::cout \<\< "TaskD\n"; });A.precede(B, C);// A runs before B and CD.succeed(B, C);// D runs after B and Cexecutor.run(taskflow).wait();
The taskflow object itself is NOT thread-safe. You should not modifying the graph while it is running, such as adding new tasks, adding new dependencies, and moving the taskflow to another.
Please refer to Cookbook to learn more about each task type and how to submit a taskflow to an executor.
class FlowBuilderclass to build a task dependency graph
Taskflow(const std::string& name)constructs a taskflow with the given nameTaskflow()constructs a taskflowTaskflow(Taskflow&& rhs)constructs a taskflow from a moved taskflow~Taskflow() defaulteddefault destructor
auto operator=(Taskflow&& rhs) -> Taskflow&move assignment operatorvoid dump(std::ostream& ostream) constdumps the taskflow to a DOT format through a std::ostream targetauto dump() const -> std::stringdumps the taskflow to a std::string of DOT formatauto num_tasks() const -> size_tqueries the number of tasks in this taskflowauto empty() const -> boolqueries if this taskflow is empty (has no tasks)void name(const std::string&)assigns a new name to this taskflowauto name() const -> const std::string&queries the name of this taskflowvoid clear()clears the associated task dependency graph
template<typename V>
void for_each_task(V&& visitor) constapplies a visitor to each task in this taskflowvoid remove_dependency(Task from, Task to)removes dependencies that go from task from to task toauto graph() -> Graph&returns a reference to the underlying graph object
constructs a taskflow with the given name
tf::Taskflow taskflow("My Taskflow");std::cout \<\< taskflow.name();// "My Taskflow"
constructs a taskflow from a moved taskflow
Constructing a taskflow taskflow1 from a moved taskflow taskflow2 will migrate the graph of taskflow2 to taskflow1. After the move, taskflow2 will become empty.
tf::Taskflow taskflow1(std::move(taskflow2));assert(taskflow2.empty());
default destructor
When the destructor is called, all tasks and their associated data (e.g., captured data) will be destroyed. It is your responsibility to ensure all submitted execution of this taskflow have completed before destroying it. For instance, the following code results in undefined behavior since the executor may still be running the taskflow while it is destroyed after the block.
{tf::Taskflow taskflow;executor.run(taskflow);}
To fix the problem, we must wait for the execution to complete before destroying the taskflow.
{tf::Taskflow taskflow;executor.run(taskflow).wait();}
move assignment operator
Moving a taskflow taskflow2 to another taskflow taskflow1 will destroy the existing graph of taskflow1 and assign it the graph of taskflow2. After the move, taskflow2 will become empty.
taskflow1 = std::move(taskflow2);assert(taskflow2.empty());
dumps the taskflow to a DOT format through a std::ostream target
taskflow.dump(std::cout);// dump the graph to the standard outputstd::ofstream ofs("output.dot");taskflow.dump(ofs);// dump the graph to the file output.dot
For dynamically spawned tasks, such as module tasks, subflow tasks, and GPU tasks, you need to run the taskflow first before you can dump the entire graph. For subflow tasks the subflow must be retained, otherwise it is cleared when joined and the child tasks not shown in the DOT graph.
tf::Task parent = taskflow.emplace([](tf::Subflow sf){sf.emplace([](){ std::cout \<\< "child\n"; });sf.retain(true);});taskflow.dump(std::cout);// this dumps only the parent tasksexecutor.run(taskflow).wait();taskflow.dump(std::cout);// this dumps both parent and child tasks
dumps the taskflow to a std::string of DOT format
This method is similar to tf::Taskflow::dump(std::ostream& ostream), but returning a string of the graph in DOT format.
queries the number of tasks in this taskflow
The number of tasks in this taskflow is defined at the first level of hierarchy. Tasks that are created dynamically, such as those via tf::Subflow, are not counted.
tf::Taskflow taskflow;auto my\_task = taskflow.emplace([](){});assert(taskflow.num\_tasks() == 1);// reassign my\_task to a subflow of four tasksmy\_task.work([](tf::Subflow& sf){sf.emplace([](){ std::cout \<\< "Task A\n"; },[](){ std::cout \<\< "Task B\n"; },[](){ std::cout \<\< "Task C\n"; },[](){ std::cout \<\< "Task D\n"; });});// subflow tasks will not be countedassert(taskflow.num\_tasks() == 1);
queries if this taskflow is empty (has no tasks)
An empty taskflow has no tasks, i.e., the return of tf::Taskflow::num_tasks is 0.
tf::Taskflow taskflow;assert(taskflow.empty() == true);taskflow.emplace([](){});assert(taskflow.empty() == false);
assigns a new name to this taskflow
taskflow.name("foo");assert(taskflow.name() == "foo");
queries the name of this taskflow
tf::Taskflow taskflow("foo");assert(taskflow.name() == "foo");
clears the associated task dependency graph
When you clear a taskflow, all tasks and their associated data (e.g., captured data in task callables) will be destroyed. The behavior of clearing a running taskflow is undefined.
applies a visitor to each task in this taskflow
A visitor is a callable that takes an argument of type tf::Task and returns nothing. The following example iterates each task in a taskflow and prints its name:
taskflow.for\_each\_task([](tf::Task task){std::cout \<\< task.name() \<\< '\n';});
removes dependencies that go from task from to task to
| Parameters |
|---|
| from |
| to |
Removing the depencency from task from to task to is equivalent to removing to from the succcessor list of from and removing from from the predecessor list of to.
tf::Taskflow taskflow;auto a = taskflow.placeholder().name("a");auto b = taskflow.placeholder().name("b");auto c = taskflow.placeholder().name("c");auto d = taskflow.placeholder().name("d");a.precede(b, c, d);assert(a.num\_successors() == 3);assert(b.num\_predecessors() == 1);assert(c.num\_predecessors() == 1);assert(d.num\_predecessors() == 1);taskflow.remove\_dependency(a, b);assert(a.num\_successors() == 2);assert(b.num\_predecessors() == 0);
returns a reference to the underlying graph object
A graph object is of type tf::Graph and stores a task dependency graph that can be executed by an tf::Executor.