<!-- iframe showing the search results (closed by default) -->
<divid="MSearchResultsWindow">
<iframesrc="javascript:void(0)" frameborder="0"
name="MSearchResults" id="MSearchResults">
</iframe>
</div>
<divclass="header">
<divclass="headertitle">
<divclass="title">C1: Create a Taskflow </div></div>
</div><!--header-->
<divclass="contents">
<divclass="textblock"><p>This chapter demonstrates how to create a task dependency graph–<aclass="el" href="classtf_1_1Taskflow.html" title="the class to create a task dependency graph ">tf::Taskflow</a>.</p>
<h1><aclass="anchor" id="WhatIsATask"></a>
What is a Task?</h1>
<p>A task in Cpp-Taskflow is a <em>callable</em> object for which the operation <ahref="https://en.cppreference.com/w/cpp/utility/functional/invoke">std::invoke</a> is applicable. It can be either a functor, a lambda expression, a bind expression, or a class objects with <code>operator()</code> overloaded. All tasks are created from <aclass="el" href="classtf_1_1Taskflow.html" title="the class to create a task dependency graph ">tf::Taskflow</a>, the class that manages a task dependency graph and its tasks. Cpp-Taskflow provides two methods, <aclass="el" href="classtf_1_1FlowBuilder.html#acab0b4ac82260f47fdb36a3244ee3aaf" title="creates an empty task ">tf::Taskflow::placeholder</a> and <aclass="el" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c" title="creates a task from a given callable object ">tf::Taskflow::emplace</a> to create a task.</p>
<divclass="fragment"><divclass="line"><aclass="code" href="classtf_1_1Taskflow.html">tf::Taskflow</a> taskflow;</div><divclass="line"><aclass="code" href="classtf_1_1Task.html">tf::Task</a> A = taskflow.<aclass="code" href="classtf_1_1FlowBuilder.html#acab0b4ac82260f47fdb36a3244ee3aaf">placeholder</a>();</div><divclass="line"><aclass="code" href="classtf_1_1Task.html">tf::Task</a> B = taskflow.<aclass="code" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([] () { <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <spanclass="stringliteral">"task B\n"</span>; });</div></div><!-- fragment --><p>Debrief: </p><ul>
<li>Line 1 creates a taskflow object, or a <em>graph</em></li>
<li>Line 2 creates an empty task </li>
<li>Line 3 creates a task from a given callable object and returns a task handle</li>
</ul>
<p>Each time you create a task including an empty one, the taskflow object adds a node to the present graph and returns a task handle of type <aclass="el" href="classtf_1_1Task.html" title="Handle to modify and access a task. ">tf::Task</a>. A task handle is a lightweight object that wraps up a particular node in a graph and provides a set of methods for you to assign different attributes to the task such as adding dependencies, naming, and assigning a new work.</p>
<li>Line 5-6 assigns a name and a work to task A, and add a precedence link to task B </li>
<li>Line 7 adds a dependency link from A to B </li>
<li>Line 9-14 dumps the task attributes</li>
</ul>
<p>Cpp-Taskflow uses the general-purpose polymorphic function wrapper <aclass="elRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/utility/functional/function.html">std::function</a> to store and invoke any callable target in a task. You need to follow its contract to create a task. For instance, the callable object must be copy constructible.</p>
<p>Cpp-Taskflow uses C++ structured binding coupled with <aclass="elRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/utility/tuple.html">std::tuple</a> to make it simple to create multiple tasks at one time.</p>
<p>A task lives with its graph and belongs to only a graph at a time, and is not destroyed until the graph gets cleaned up. The lifetime of a task refers to the user-given callable object, including captured values. As long as the graph is alive, all the associated tasks exist. It is your responsibility to keep tasks and graph alive during their execution.</p>
<p>This example demonstrates how to modify a task's attributes using methods defined in the task handler.</p>
<divclass="fragment"><divclass="line"> 1: #include <taskflow/taskflow.hpp></div><divclass="line"> 2:</div><divclass="line"> 3: <spanclass="keywordtype">int</span> main() {</div><divclass="line"> 4:</div><divclass="line"> 5: <aclass="code" href="classtf_1_1Taskflow.html">tf::Taskflow</a> taskflow;</div><divclass="line"> 6:</div><divclass="line"> 7: <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/container/vector.html">std::vector<tf::Task></a> tasks = { </div><divclass="line"> 8: taskflow.<aclass="code" href="classtf_1_1FlowBuilder.html#acab0b4ac82260f47fdb36a3244ee3aaf">placeholder</a>(), <spanclass="comment">// create a task with no work</span></div><divclass="line"> 9: taskflow.<aclass="code" href="classtf_1_1FlowBuilder.html#acab0b4ac82260f47fdb36a3244ee3aaf">placeholder</a>() <spanclass="comment">// create a task with no work</span></div><divclass="line">10: };</div><divclass="line">11:</div><divclass="line">12: tasks[0].name(<spanclass="stringliteral">"This is Task 0"</span>);</div><divclass="line">13: tasks[1].name(<spanclass="stringliteral">"This is Task 1"</span>);</div><divclass="line">14: tasks[0].precede(tasks[1]);</div><divclass="line">15:</div><divclass="line">16: <spanclass="keywordflow">for</span>(<spanclass="keyword">auto</span> task : tasks) { <spanclass="comment">// print out each task's attributes</span></div><divclass="line">17: <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << task.name() << <spanclass="stringliteral">": "</span></div><divclass="line">18: << <spanclass="stringliteral">"num_dependents="</span> << task.num_dependents() << <spanclass="stringliteral">", "</span></div><divclass="line">19: << <spanclass="stringliteral">"num_successors="</span> << task.num_successors() << <spanclass="charliteral">'\n'</span>;</div><divclass="line">20: }</div><divclass="line">21:</div><divclass="line">22: taskflow.<aclass="code" href="classtf_1_1Taskflow.html#ac433018262e44b12c4cc9f0c4748d758">dump</a>(<aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a>); <spanclass="comment">// dump the taskflow graph</span></div><divclass="line">23:</div><divclass="line">24: tasks[0].work([](){ <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <spanclass="stringliteral">"got a new work!\n"</span>; });</div><divclass="line">25: tasks[1].work([](){ <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <spanclass="stringliteral">"got a new work!\n"</span>; });</div><divclass="line">26:</div><divclass="line">27: <spanclass="keywordflow">return</span> 0;</div><divclass="line">28: }</div></div><!-- fragment --><p>The output of this program looks like the following:</p>
<divclass="fragment"><divclass="line">This is Task 0: num_dependents=0, num_successors=1</div><divclass="line">This is Task 1: num_dependents=1, num_successors=0</div><divclass="line">digraph Taskflow {</div><divclass="line">"This is Task 1";</div><divclass="line">"This is Task 0";</div><divclass="line">"This is Task 0" -> "This is Task 1";</div><divclass="line">}</div></div><!-- fragment --><p>Debrief: </p><ul>
<li>Line 5 creates a taskflow object </li>
<li>Line 7-10 creates two tasks with empty target and stores the corresponding task handles in a vector </li>
<li>Line 12-13 names the two tasks with human-readable strings </li>
<li>Line 14 adds a dependency link from the first task to the second task </li>
<li>Line 16-20 prints out the name of each task, the number of dependents, and the number of successors </li>
<li>Line 22 dumps the task dependency graph to a <ahref="https://dreampuf.github.io/GraphvizOnline/">GraphViz Online</a> format (dot) </li>
<li>Line 24-25 assigns a new target to each task</li>
</ul>
<p>You can change the name and work of a task at anytime before running the graph. The later assignment overwrites the previous values.</p>
<p>A powerful feature of <aclass="el" href="classtf_1_1Taskflow.html" title="the class to create a task dependency graph ">tf::Taskflow</a> is its <em>composable</em> interface. You can break down a large parallel workload into smaller pieces each designed to run a specific task dependency graph. This largely facilitates the <em>modularity</em> of writing a parallel task program.</p>
<li>Line 1-12 creates a taskflow of three tasks f1A, f1B, and f1C with f1A and f1B preceding f1C </li>
<li>Line 17-30 creates a taskflow of four tasks f2A, f2B, f2C, and f2D </li>
<li>Line 32 creates a module task from taskflow f1 through the method <aclass="el" href="classtf_1_1Taskflow.html#a21b96ca779cc68d1117fdf1b053d11ee" title="creates a module task from a taskflow ">Taskflow::composed_of</a></li>
<li>Line 33 enforces task f2C to run before the module task </li>
<li>Line 34 enforces the module task to run before task f2D</li>
</ul>
<p>The task created from <aclass="el" href="classtf_1_1Taskflow.html#a21b96ca779cc68d1117fdf1b053d11ee" title="creates a module task from a taskflow ">Taskflow::composed_of</a> is a <em>module</em> task that runs on a taskflow. A module task does not owns any taskflow but maintains a soft mapping to use during its execution context. You can create multiple module tasks from the same taskflow but only one module task can run at one time. For example, the following composition is valid. Even though the two module tasks <code>module1</code> and <code>module2</code> refer to the same taskflow <code>F1</code>, the dependency link prevents <code>F1</code> from multiple executions at the same time.</p>
<p>However, the following composition is <em>invalid</em>. Both module tasks refer to the same taskflow. They can not run at the same time because they are associated with the same graph.</p>