Module Algorithm
Taskflow provides template methods that let users create reusable building blocks called modules. Users can connect modules together to build more complex parallel algorithms.
Include the Header
You need to include the header file, taskflow/
, for creating a module task over a schedulable graph target.
#include <taskflow/algorithm/module.hpp>
What is a Module Task
Similar to Composable Tasking, but in a more generic setting, the template function, tf::
tf::Executor executor; tf::Taskflow A; tf::Taskflow B; tf::Taskflow C; tf::Taskflow D; A.emplace([](){ printf("Taskflow A\n"); }); B.emplace([](){ printf("Taskflow B\n"); }); C.emplace([](){ printf("Taskflow C\n"); }); D.emplace([](){ printf("Taskflow D\n"); }); // launch the four taskflows using asynchronous tasking executor.async(tf::make_module_task(A)); executor.async(tf::make_module_task(B)); executor.async(tf::make_module_task(C)); executor.async(tf::make_module_task(D)); executor.wait_for_all();
Since the four taskflows are launched asynchronously without any dependencies between them, we can observe any order of the output message:
# one possible output Taskflow B Taskflow C Taskflow A Taskflow D # another possible output Taskflow D Taskflow A Taskflow B Taskflow C
If you need to enforce dependencies among these four taskflows, you can use dependent-async tasks. The example below launches the four taskflows one by one in sequential:
tf::Executor executor; tf::Taskflow A; tf::Taskflow B; tf::Taskflow C; tf::Taskflow D; A.emplace([](){ printf("Taskflow A\n"); }); B.emplace([](){ printf("Taskflow B\n"); }); C.emplace([](){ printf("Taskflow C\n"); }); D.emplace([](){ printf("Taskflow D\n"); }); auto TA = executor.silent_dependent_async(tf::make_module_task(A)); auto TB = executor.silent_dependent_async(tf::make_module_task(B), TA); auto TC = executor.silent_dependent_async(tf::make_module_task(C), TB); auto [TD, FD] = executor.dependent_async(tf::make_module_task(D), TC); FD.get();
# dependent-async tasks enforce a sequential execution of the four taskflows Taskflow A Taskflow B Taskflow C Taskflow D
The module task maker, tf::
// approach 1: composition using composed_of tf::Task m1 = taskflow1.composed_of(taskflow2); // approach 2: composition using make_module_task tf::Task m1 = taskflow1.emplace(tf::make_module_task(taskflow2));
Create a Module Task over a Custom Graph
In addition to encapsulate taskflow graphs, you can create a module task to schedule a custom graph target. A schedulable target (of type T
) must define the method T::graph()
that returns a reference to the tf::T
. The following example defines a custom graph that can be scheduled through making module tasks:
struct CustomGraph { tf::Graph graph; CustomGraph() { // use flow builder to inherit all task creation methods in tf::Taskflow tf::FlowBuilder builder(graph); tf::Task task = builder.emplace([](){ std::cout << "a task\n"; // static task }); } // returns a reference to the graph for taskflow composition Graph& graph() { return graph; } }; CustomGraph target; executor.async(tf::make_module_task(target));