class
FlowBuilderclass to build a task dependency graph
Contents
The class provides essential methods to construct a task dependency graph from which tf::
Derived classes
Constructors, destructors, conversion operators
- FlowBuilder(Graph& graph)
- constructs a flow builder with a graph
Public functions
-
template<typename C, std::enable_if_t<is_auto emplace(C&& callable) -> Task
static_ task_ v<C>, void>* = nullptr> - creates a static task
-
template<typename C, std::enable_if_t<is_auto emplace(C&& callable) -> Task
dynamic_ task_ v<C>, void>* = nullptr> - creates a dynamic task
-
template<typename C, std::enable_if_t<is_auto emplace(C&& callable) -> Task
condition_ task_ v<C>, void>* = nullptr> - creates a condition task
-
template<typename C, std::enable_if_t<is_auto emplace(C&& callable) -> Task
multi_ condition_ task_ v<C>, void>* = nullptr> - creates a multi-condition task
-
template<typename... C, std::enable_if_t<(sizeof...(C)>1), void>* = nullptr>auto emplace(C && ... callables) -> auto
- creates multiple tasks from a list of callable objects
- void erase(Task task)
- removes a task from a taskflow
-
template<typename T>auto composed_of(T& object) -> Task
- creates a module task for the target object
- auto placeholder() -> Task
- creates a placeholder task
-
template<typename C, std::enable_if_t<is_auto emplace(C&& callable) -> Task
cudaflow_ task_ v<C>, void>* = nullptr> - creates a cudaFlow task on the caller's GPU device context
-
template<typename C, typename D, std::enable_if_t<is_auto emplace_on(C&& callable, D&& device) -> Task
cudaflow_ task_ v<C>, void>* = nullptr> - creates a cudaFlow task on the given device
-
template<typename C, std::enable_if_t<is_auto emplace(C&& callable) -> Task
syclflow_ task_ v<C>, void>* = nullptr> - creates a syclFlow task on the default queue
-
template<typename C, typename Q, std::enable_if_t<is_auto emplace_on(C&& callable, Q&& queue) -> Task
syclflow_ task_ v<C>, void>* = nullptr> - creates a syclFlow task on the given queue
-
template<typename C, std::enable_if_t<is_auto emplace(C&& callable) -> Task
runtime_ task_ v<C>, void>* = nullptr> - creates a runtime task
-
void linearize(std::
vector<Task>& tasks) - adds adjacent dependency links to a linear list of tasks
-
void linearize(std::
initializer_list<Task> tasks) - adds adjacent dependency links to a linear list of tasks
-
template<typename B, typename E, typename C>auto for_each(B first, E last, C callable) -> Task
- constructs a STL-styled parallel-for task
-
template<typename B, typename E, typename S, typename C>auto for_each_index(B first, E last, S step, C callable) -> Task
- constructs a parallel-transform task
-
template<typename B, typename E, typename O, typename C>auto transform(B first1, E last1, O d_first, C c) -> Task
- constructs a parallel-transform task
-
template<typename B1, typename E1, typename B2, typename O, typename C>auto transform(B1 first1, E1 last1, B2 first2, O d_first, C c) -> Task
- constructs a parallel-transform task
-
template<typename B, typename E, typename T, typename O>auto reduce(B first, E last, T& init, O bop) -> Task
- constructs a STL-styled parallel-reduce task
-
template<typename B, typename E, typename T, typename BOP, typename UOP>auto transform_reduce(B first, E last, T& init, BOP bop, UOP uop) -> Task
- constructs a STL-styled parallel transform-reduce task
-
template<typename B, typename E, typename C>auto sort(B first, E last, C cmp) -> Task
- constructs a dynamic task to perform STL-styled parallel sort
-
template<typename B, typename E>auto sort(B first, E last) -> Task
- constructs a dynamic task to perform STL-styled parallel sort using the
std::less<T>
comparator, whereT
is the element type
Protected variables
Function documentation
template<typename C, std::enable_if_t<is_ static_ task_ v<C>, void>* = nullptr>
Task tf:: FlowBuilder:: emplace(C&& callable)
creates a static task
Template parameters | |
---|---|
C | callable type constructible from std::function<void()> |
Parameters | |
callable | callable to construct a static task |
Returns | a tf:: |
The following example creates a static task.
tf::Task static_task = taskflow.emplace([](){});
Please refer to Static Tasking for details.
template<typename C, std::enable_if_t<is_ dynamic_ task_ v<C>, void>* = nullptr>
Task tf:: FlowBuilder:: emplace(C&& callable)
creates a dynamic task
Template parameters | |
---|---|
C | callable type constructible from std::function<void(tf::Subflow&)> |
Parameters | |
callable | callable to construct a dynamic task |
Returns | a tf:: |
The following example creates a dynamic task (tf::
tf::Task dynamic_task = taskflow.emplace([](tf::Subflow& sf){ tf::Task static_task1 = sf.emplace([](){}); tf::Task static_task2 = sf.emplace([](){}); });
Please refer to Dynamic Tasking for details.
template<typename C, std::enable_if_t<is_ condition_ task_ v<C>, void>* = nullptr>
Task tf:: FlowBuilder:: emplace(C&& callable)
creates a condition task
Template parameters | |
---|---|
C | callable type constructible from std::function<int()> |
Parameters | |
callable | callable to construct a condition task |
Returns | a tf:: |
The following example creates an if-else block using one condition task and three static tasks.
tf::Taskflow taskflow; auto [init, cond, yes, no] = taskflow.emplace( [] () { }, [] () { return 0; }, [] () { std::cout << "yes\n"; }, [] () { std::cout << "no\n"; } ); // executes yes if cond returns 0, or no if cond returns 1 cond.precede(yes, no); cond.succeed(init);
Please refer to Conditional Tasking for details.
template<typename C, std::enable_if_t<is_ multi_ condition_ task_ v<C>, void>* = nullptr>
Task tf:: FlowBuilder:: emplace(C&& callable)
creates a multi-condition task
Template parameters | |
---|---|
C | callable type constructible from std:: |
Parameters | |
callable | callable to construct a multi-condition task |
Returns | a tf:: |
The following example creates a multi-condition task that selectively jumps to two successor tasks.
tf::Taskflow taskflow; auto [init, cond, branch1, branch2, branch3] = taskflow.emplace( [] () { }, [] () { return tf::SmallVector{0, 2}; }, [] () { std::cout << "branch1\n"; }, [] () { std::cout << "branch2\n"; }, [] () { std::cout << "branch3\n"; } ); // executes branch1 and branch3 when cond returns 0 and 2 cond.precede(branch1, branch2, branch3); cond.succeed(init);
Please refer to Conditional Tasking for details.
template<typename... C, std::enable_if_t<(sizeof...(C)>1), void>* = nullptr>
auto tf:: FlowBuilder:: emplace(C && ... callables)
creates multiple tasks from a list of callable objects
Template parameters | |
---|---|
C | callable types |
Parameters | |
callables | one or multiple callable objects constructible from each task category |
Returns | a tf:: |
The method returns a tuple of tasks each corresponding to the given callable target. You can use structured binding to get the return tasks one by one. The following example creates four static tasks and assign them to A
, B
, C
, and D
using structured binding.
auto [A, B, C, D] = taskflow.emplace( [] () { std::cout << "A"; }, [] () { std::cout << "B"; }, [] () { std::cout << "C"; }, [] () { std::cout << "D"; } );
void tf:: FlowBuilder:: erase(Task task)
removes a task from a taskflow
Parameters | |
---|---|
task | task to remove |
Removes a task and its input and output dependencies from the graph associated with the flow builder. If the task does not belong to the graph, nothing will happen.
tf::Task A = taskflow.emplace([](){ std::cout << "A"; }); tf::Task B = taskflow.emplace([](){ std::cout << "B"; }); tf::Task C = taskflow.emplace([](){ std::cout << "C"; }); tf::Task D = taskflow.emplace([](){ std::cout << "D"; }); A.precede(B, C, D); // erase A from the taskflow and its dependencies to B, C, and D taskflow.erase(A);
template<typename T>
Task tf:: FlowBuilder:: composed_of(T& object)
creates a module task for the target object
Template parameters | |
---|---|
T | target object type |
Parameters | |
object | a custom object that defines the method T::graph() |
Returns | a tf:: |
The example below demonstrates a taskflow composition using the composed_of
method.
tf::Taskflow t1, t2; t1.emplace([](){ std::cout << "t1"; }); // t2 is partially composed of t1 tf::Task comp = t2.composed_of(t1); tf::Task init = t2.emplace([](){ std::cout << "t2"; }); init.precede(comp);
The taskflow object t2
is composed of another taskflow object t1
, preceded by another static task init
. When taskflow t2
is submitted to an executor, init
will run first and then comp
which spwans its definition in taskflow t1
.
The target object
being composed must define the method T::graph()
that returns a reference to a graph object of type tf::
// custom struct struct MyObj { tf::Graph graph; MyObj() { tf::FlowBuilder builder(graph); tf::Task task = builder.emplace([](){ std::cout << "a task\n"; // static task }); } Graph& graph() { return graph; } }; MyObj obj; tf::Task comp = taskflow.composed_of(obj);
Please refer to Composable Tasking for details.
Task tf:: FlowBuilder:: placeholder()
creates a placeholder task
Returns | a tf:: |
---|
A placeholder task maps to a node in the taskflow graph, but it does not have any callable work assigned yet. A placeholder task is different from an empty task handle that does not point to any node in a graph.
// create a placeholder task with no callable target assigned tf::Task placeholder = taskflow.placeholder(); assert(placeholder.empty() == false && placeholder.has_work() == false); // create an empty task handle tf::Task task; assert(task.empty() == true); // assign the task handle to the placeholder task task = placeholder; assert(task.empty() == false && task.has_work() == false);
template<typename C, std::enable_if_t<is_ cudaflow_ task_ v<C>, void>* = nullptr>
Task tf:: FlowBuilder:: emplace(C&& callable)
creates a cudaFlow task on the caller's GPU device context
Template parameters | |
---|---|
C | callable type constructible from std::function<void(tf::cudaFlow&)> |
Returns | a tf:: |
This method is equivalent to calling tf::FlowBuilder::emplace_on(callable, d) where d
is the caller's device context. The following example creates a cudaFlow of two kernel tasks, task1
and task2
, where task1
runs before task2
.
taskflow.emplace([&](tf::cudaFlow& cf){ // create two kernel tasks tf::cudaTask task1 = cf.kernel(grid1, block1, shm1, kernel1, args1); tf::cudaTask task2 = cf.kernel(grid2, block2, shm2, kernel2, args2); // kernel1 runs before kernel2 task1.precede(task2); });
Please refer to GPU Tasking (cudaFlow) and GPU Tasking (cudaFlowCapturer) for details.
template<typename C, typename D, std::enable_if_t<is_ cudaflow_ task_ v<C>, void>* = nullptr>
Task tf:: FlowBuilder:: emplace_on(C&& callable,
D&& device)
creates a cudaFlow task on the given device
Template parameters | |
---|---|
C | callable type constructible from std::function<void(tf::cudaFlow&)> |
D | device type, either int or std::ref<int> (stateful) |
Returns | a tf:: |
The following example creates a cudaFlow of two kernel tasks, task1
and task2
on GPU 2
, where task1
runs before task2
taskflow.emplace_on([&](tf::cudaFlow& cf){ // create two kernel tasks tf::cudaTask task1 = cf.kernel(grid1, block1, shm1, kernel1, args1); tf::cudaTask task2 = cf.kernel(grid2, block2, shm2, kernel2, args2); // kernel1 runs before kernel2 task1.precede(task2); }, 2);
template<typename C, std::enable_if_t<is_ syclflow_ task_ v<C>, void>* = nullptr>
Task tf:: FlowBuilder:: emplace(C&& callable)
creates a syclFlow task on the default queue
Template parameters | |
---|---|
C | callable type constructible from std::function<void(tf::syclFlow&)> |
Parameters | |
callable | a callable that takes a referenced tf:: |
Returns | a tf:: |
The following example creates a syclFlow on the default queue to submit two kernel tasks, task1
and task2
, where task1
runs before task2
.
taskflow.emplace([&](tf::syclFlow& cf){ // create two single-thread kernel tasks tf::syclTask task1 = cf.single_task([](){}); tf::syclTask task2 = cf.single_task([](){}); // kernel1 runs before kernel2 task1.precede(task2); });
template<typename C, typename Q, std::enable_if_t<is_ syclflow_ task_ v<C>, void>* = nullptr>
Task tf:: FlowBuilder:: emplace_on(C&& callable,
Q&& queue)
creates a syclFlow task on the given queue
Template parameters | |
---|---|
C | callable type constructible from std::function<void(tf::syclFlow&)> |
Q | queue type |
Parameters | |
callable | a callable that takes a referenced tf:: |
queue | a queue of type sycl::queue |
Returns | a tf:: |
The following example creates a syclFlow on the given queue to submit two kernel tasks, task1
and task2
, where task1
runs before task2
.
taskflow.emplace_on([&](tf::syclFlow& cf){ // create two single-thread kernel tasks tf::syclTask task1 = cf.single_task([](){}); tf::syclTask task2 = cf.single_task([](){}); // kernel1 runs before kernel2 task1.precede(task2); }, queue);
template<typename C, std::enable_if_t<is_ runtime_ task_ v<C>, void>* = nullptr>
Task tf:: FlowBuilder:: emplace(C&& callable)
creates a runtime task
Template parameters | |
---|---|
C | callable type constructible from std::function<void(tf::Runtime&)> |
Parameters | |
callable | callable to construct a runtime task |
Returns | a tf:: |
The following example creates a runtime task that enables in-task control over the running executor.
tf::Task runtime_task = taskflow.emplace([](tf::Runtime& rt){ auto& executor = rt.executor(); std::cout << executor.num_workers() << '\n'; });
Please refer to Runtime Tasking for details.
void tf:: FlowBuilder:: linearize(std:: vector<Task>& tasks)
adds adjacent dependency links to a linear list of tasks
Parameters | |
---|---|
tasks | a vector of tasks |
This member function creates linear dependencies over a vector of tasks.
tf::Task A = taskflow.emplace([](){ std::cout << "A"; }); tf::Task B = taskflow.emplace([](){ std::cout << "B"; }); tf::Task C = taskflow.emplace([](){ std::cout << "C"; }); tf::Task D = taskflow.emplace([](){ std::cout << "D"; }); std::vector<tf::Task> tasks {A, B, C, D} taskflow.linearize(tasks); // A->B->C->D
void tf:: FlowBuilder:: linearize(std:: initializer_list<Task> tasks)
adds adjacent dependency links to a linear list of tasks
Parameters | |
---|---|
tasks | an initializer list of tasks |
This member function creates linear dependencies over a list of tasks.
tf::Task A = taskflow.emplace([](){ std::cout << "A"; }); tf::Task B = taskflow.emplace([](){ std::cout << "B"; }); tf::Task C = taskflow.emplace([](){ std::cout << "C"; }); tf::Task D = taskflow.emplace([](){ std::cout << "D"; }); taskflow.linearize({A, B, C, D}); // A->B->C->D
template<typename B, typename E, typename C>
Task tf:: FlowBuilder:: for_each(B first,
E last,
C callable)
constructs a STL-styled parallel-for task
Template parameters | |
---|---|
B | beginning iterator type |
E | ending iterator type |
C | callable type |
Parameters | |
first | iterator to the beginning (inclusive) |
last | iterator to the end (exclusive) |
callable | a callable object to apply to the dereferenced iterator |
Returns | a tf:: |
The task spawns a subflow that applies the callable object to each object obtained by dereferencing every iterator in the range [first, last)
. This method is equivalent to the parallel execution of the following loop:
for(auto itr=first; itr!=last; itr++) { callable(*itr); }
Arguments templated to enable stateful range using std::
Please refer to Parallel Iterations for details.
template<typename B, typename E, typename S, typename C>
Task tf:: FlowBuilder:: for_each_index(B first,
E last,
S step,
C callable)
constructs a parallel-transform task
Template parameters | |
---|---|
B | beginning index type (must be integral) |
E | ending index type (must be integral) |
S | step type (must be integral) |
C | callable type |
Parameters | |
first | index of the beginning (inclusive) |
last | index of the end (exclusive) |
step | step size |
callable | a callable object to apply to each valid index |
Returns | a tf:: |
The task spawns a subflow that applies the callable object to each index in the range [first, last)
with the step size. This method is equivalent to the parallel execution of the following loop:
// case 1: step size is positive for(auto i=first; i<last; i+=step) { callable(i); } // case 2: step size is negative for(auto i=first, i>last; i+=step) { callable(i); }
Arguments are templated to enable stateful range using std::
Please refer to Parallel Iterations for details.
template<typename B, typename E, typename O, typename C>
Task tf:: FlowBuilder:: transform(B first1,
E last1,
O d_first,
C c)
constructs a parallel-transform task
Template parameters | |
---|---|
B | beginning input iterator type |
E | ending input iterator type |
O | output iterator type |
C | callable type |
Parameters | |
first1 | iterator to the beginning of the first range |
last1 | iterator to the end of the first range |
d_first | iterator to the beginning of the output range |
c | an unary callable to apply to dereferenced input elements |
Returns | a tf:: |
The task spawns a subflow that applies the callable object to an input range and stores the result in another output range. This method is equivalent to the parallel execution of the following loop:
while (first1 != last1) { *d_first++ = c(*first1++); }
Arguments are templated to enable stateful range using std::
template<typename B1, typename E1, typename B2, typename O, typename C>
Task tf:: FlowBuilder:: transform(B1 first1,
E1 last1,
B2 first2,
O d_first,
C c)
constructs a parallel-transform task
Template parameters | |
---|---|
B1 | beginning input iterator type for the first input range |
E1 | ending input iterator type for the first input range |
B2 | beginning input iterator type for the first second range |
O | output iterator type |
C | callable type |
Parameters | |
first1 | iterator to the beginning of the first input range |
last1 | iterator to the end of the first input range |
first2 | iterator to the beginning of the second input range |
d_first | iterator to the beginning of the output range |
c | a binary operator to apply to dereferenced input elements |
Returns | a tf:: |
The task spawns a subflow that applies the callable object to two input ranges and stores the result in another output range. This method is equivalent to the parallel execution of the following loop:
while (first1 != last1) { *d_first++ = c(*first1++, *first2++); }
Arguments are templated to enable stateful range using std::
template<typename B, typename E, typename T, typename O>
Task tf:: FlowBuilder:: reduce(B first,
E last,
T& init,
O bop)
constructs a STL-styled parallel-reduce task
Template parameters | |
---|---|
B | beginning iterator type |
E | ending iterator type |
T | result type |
O | binary reducer type |
Parameters | |
first | iterator to the beginning (inclusive) |
last | iterator to the end (exclusive) |
init | initial value of the reduction and the storage for the reduced result |
bop | binary operator that will be applied |
Returns | a tf:: |
The task spawns a subflow to perform parallel reduction over init
and the elements in the range [first, last)
. The reduced result is store in init
. This method is equivalent to the parallel execution of the following loop:
for(auto itr=first; itr!=last; itr++) { init = bop(init, *itr); }
Arguments are templated to enable stateful range using std::
Please refer to Parallel Reduction for details.
template<typename B, typename E, typename T, typename BOP, typename UOP>
Task tf:: FlowBuilder:: transform_reduce(B first,
E last,
T& init,
BOP bop,
UOP uop)
constructs a STL-styled parallel transform-reduce task
Template parameters | |
---|---|
B | beginning iterator type |
E | ending iterator type |
T | result type |
BOP | binary reducer type |
UOP | unary transformion type |
Parameters | |
first | iterator to the beginning (inclusive) |
last | iterator to the end (exclusive) |
init | initial value of the reduction and the storage for the reduced result |
bop | binary operator that will be applied in unspecified order to the results of uop |
uop | unary operator that will be applied to transform each element in the range to the result type |
Returns | a tf:: |
The task spawns a subflow to perform parallel reduction over init
and the transformed elements in the range [first, last)
. The reduced result is store in init
. This method is equivalent to the parallel execution of the following loop:
for(auto itr=first; itr!=last; itr++) { init = bop(init, uop(*itr)); }
Arguments are templated to enable stateful range using std::
Please refer to Parallel Reduction for details.
template<typename B, typename E, typename C>
Task tf:: FlowBuilder:: sort(B first,
E last,
C cmp)
constructs a dynamic task to perform STL-styled parallel sort
Template parameters | |
---|---|
B | beginning iterator type (random-accessible) |
E | ending iterator type (random-accessible) |
C | comparator type |
Parameters | |
first | iterator to the beginning (inclusive) |
last | iterator to the end (exclusive) |
cmp | comparison function object |
The task spawns a subflow to parallelly sort elements in the range [first, last)
.
Arguments are templated to enable stateful range using std::
Please refer to Parallel Sort for details.
template<typename B, typename E>
Task tf:: FlowBuilder:: sort(B first,
E last)
constructs a dynamic task to perform STL-styled parallel sort using the std::less<T>
comparator, where T
is the element type
Template parameters | |
---|---|
B | beginning iterator type (random-accessible) |
E | ending iterator type (random-accessible) |
Parameters | |
first | iterator to the beginning (inclusive) |
last | iterator to the end (exclusive) |
The task spawns a subflow to parallelly sort elements in the range [first, last)
using the std::less<T>
comparator, where T
is the dereferenced iterator type.
Arguments are templated to enable stateful range using std::
Please refer to Parallel Sort for details.