forked from taskflow/taskflow
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathchapter7.html
More file actions
142 lines (140 loc) · 24.2 KB
/
chapter7.html
File metadata and controls
142 lines (140 loc) · 24.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
<!-- HTML header for doxygen 1.8.13-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Cpp-Taskflow</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript">
$(document).ready(initResizable);
</script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<script type="text/javascript">
$(document).ready(function() { init_search(); });
</script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
<tbody>
<tr style="height: 56px;">
<td id="projectalign" style="padding-left: 0.5em;">
<div id="projectname"><a href="https://github.com/cpp-taskflow/cpp-taskflow">Cpp-Taskflow</a>
 <span id="projectnumber">2.1.0</span>
</div>
</td>
<td> <div id="MSearchBox" class="MSearchBoxInactive">
<span class="left">
<img id="MSearchSelect" src="search/mag_sel.png"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
alt=""/>
<input type="text" id="MSearchField" value="Search" accesskey="S"
onfocus="searchBox.OnSearchFieldFocus(true)"
onblur="searchBox.OnSearchFieldFocus(false)"
onkeyup="searchBox.OnSearchFieldChange(event)"/>
</span><span class="right">
<a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
</span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "search",false,'Search');
</script>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
<div id="nav-tree">
<div id="nav-tree-contents">
<div id="nav-sync" class="sync"></div>
</div>
</div>
<div id="splitbar" style="-moz-user-select:none;"
class="ui-resizable-handle">
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){initNavTree('chapter7.html','');});
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
onmouseover="return searchBox.OnSearchSelectShow()"
onmouseout="return searchBox.OnSearchSelectHide()"
onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>
<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0"
name="MSearchResults" id="MSearchResults">
</iframe>
</div>
<div class="header">
<div class="headertitle">
<div class="title">C7: Framework (Experimental) </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>It is much more convenient to have a reusable task dependency graph which will persist after execution. Reuse existing graphs avoids the overhead of graph construction and also allows a graph to continue on the timepoint left from previous execution. The <em>framework</em> - <a class="el" href="classtf_1_1Framework.html">tf::Framework</a> is designed for this purpose. In this chapter we introduce the concept of framework and demonstrate how to use it.</p>
<h1><a class="anchor" id="C7_CreateAFramework"></a>
Create a Framework</h1>
<p>In Cpp-Taskflow a framework contains a task dependency graph that is independent of a taskflow object and will persist after execution. Framework shares the same APIs as those in a taskflow object: <a class="el" href="classtf_1_1FlowBuilder.html#acab0b4ac82260f47fdb36a3244ee3aaf" title="creates an empty task ">tf::Taskflow::placeholder</a>, <a class="el" href="classtf_1_1FlowBuilder.html#a7285613836c840e22b8511d447734c87" title="creates a task from a given callable object without access to the result ">tf::Taskflow::silent_emplace</a>, and <a class="el" href="classtf_1_1FlowBuilder.html#a468ddceae9c77728fbaef0f70d9fd11c" title="creates a task from a given callable object ">tf::Taskflow::emplace</a> to create a task. The code below shows how to create a framework with three tasks.</p>
<div class="fragment"><div class="line"><span class="comment">// Declare a framework </span></div><div class="line"><a class="code" href="classtf_1_1Framework.html">tf::Framework</a> f;</div><div class="line"></div><div class="line"><span class="comment">// Add three tasks into the framework</span></div><div class="line"><span class="keyword">auto</span> A = f.<a class="code" href="classtf_1_1FlowBuilder.html#a7285613836c840e22b8511d447734c87">silent_emplace</a>([](){ <a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <span class="stringliteral">"This is TaskA\n"</span>; });</div><div class="line"><span class="keyword">auto</span> B = f.<a class="code" href="classtf_1_1FlowBuilder.html#acab0b4ac82260f47fdb36a3244ee3aaf">placeholder</a>();</div><div class="line"><span class="keyword">auto</span> [C, FuC] = f.<a class="code" href="classtf_1_1FlowBuilder.html#a468ddceae9c77728fbaef0f70d9fd11c">emplace</a>([] () { <a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <span class="stringliteral">"This is TaskC\n"</span>; });</div><div class="line"></div><div class="line"><span class="comment">// Build precedence between tasks</span></div><div class="line">A.precede(B, C);</div></div><!-- fragment --><h1><a class="anchor" id="C7_ExecuteAFramework"></a>
Execute a Framework</h1>
<p>To execute a framework, you need to create a tf::Taskflow object as the executor and use any of these methods: <a class="el" href="classtf_1_1BasicTaskflow.html#af8ebf13bc439f87077c663a3c1008eea" title="runs the framework w/o callback to threads and returns immediately ">tf::Taskflow::run</a>, <a class="el" href="classtf_1_1BasicTaskflow.html#acae12080c60f087421317c7681c06f0c" title="silently runs the framework w/ callback to threads and returns immediately ">tf::Taskflow::silent_run</a>, <a class="el" href="classtf_1_1BasicTaskflow.html#a5fc02a698b067e30562f4b7ae39acfaf" title="runs the framework for N times w/o a callback to threads and returns immediately ">tf::Taskflow::run_n</a> or <a class="el" href="classtf_1_1BasicTaskflow.html#a8276dc863390e0f3e0bc53f5cf357338" title="silently runs the framework N times w/ a callback to threads and returns immediately ...">tf::Taskflow::silent_run_n</a> to dispatch the framework to threads for execution. The run and silent_run methods only execute the framework once while run_n and silent_run_n methods can take an integral number <em>N</em> and repeat execution <em>N</em> times. The <em>run</em> method returns a <a class="elRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/thread/shared_future.html">std::shared_future</a> object that allows access to the execution status while <em>silent_run</em> returns nothing. A callback can be passed to all methods and will be invoked after every execution of the framework. The code below shows how to run a framework</p>
<div class="fragment"><div class="line"> 1: <span class="comment">// Declare a framework </span></div><div class="line"> 2: <a class="code" href="classtf_1_1Framework.html">tf::Framework</a> f;</div><div class="line"> 3: </div><div class="line"> 4: <span class="comment">// Add three tasks into the framework</span></div><div class="line"> 5: <span class="keyword">auto</span> [A, B, C] = f.<a class="code" href="classtf_1_1FlowBuilder.html#a7285613836c840e22b8511d447734c87">silent_emplace</a>(</div><div class="line"> 6: [] () { <a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <span class="stringliteral">"This is TaskA\n"</span>; },</div><div class="line"> 7: [] () { <a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <span class="stringliteral">"This is TaskB\n"</span>; },</div><div class="line"> 8: [] () { <a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <span class="stringliteral">"This is TaskC\n"</span>; },</div><div class="line"> 9: );</div><div class="line">10: </div><div class="line">11: <span class="comment">// Build precedence between tasks</span></div><div class="line">12: A.precede(B, C); </div><div class="line">13: </div><div class="line">14: <span class="comment">// Declare a taskflow object</span></div><div class="line">15: <a class="code" href="classtf_1_1BasicTaskflow.html">tf::Taskflow</a> taskflow;</div><div class="line">16: </div><div class="line">17: <span class="keyword">auto</span> fu = taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#af8ebf13bc439f87077c663a3c1008eea">run</a>(f);</div><div class="line">18: fu.get();</div><div class="line">19: taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#af8ebf13bc439f87077c663a3c1008eea">run</a>(f, [](){ <a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <span class="stringliteral">"End of one execution\n"</span>; }).<span class="keyword">get</span>();</div><div class="line">20: </div><div class="line">21: taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a8276dc863390e0f3e0bc53f5cf357338">silent_run_n</a>(f, 4);</div><div class="line">22: taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a37ef86998f23ee7315be032c40fe815e">wait_for_all</a>();</div><div class="line">23: </div><div class="line">24: taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a5fc02a698b067e30562f4b7ae39acfaf">run_n</a>(f, 4, [](){ <a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <span class="stringliteral">"End of one execution\n"</span>; }).<span class="keyword">get</span>();</div></div><!-- fragment --><p>Debrief:</p>
<ul>
<li>Line 1-12 creates a framework composed of three tasks </li>
<li>Line 15 creates a taskflow object as the executor </li>
<li>Line 17-18 runs the framework once and use <em>get()</em> to wait for completion </li>
<li>Line 19 runs the framework once with a callback </li>
<li>Line 21-22 silently runs the framework four times and use <em>wait_for_all()</em> to wait for completion </li>
<li>Line 24 runs the framework with a callback four times and use <em>get()</em> to wait for completion</li>
</ul>
<h1><a class="anchor" id="C7_LifeTimeOfAFramework"></a>
Lifetime of a Framework</h1>
<p>Since a taskflow object does not own a framework, a running framework <b>must remain alive</b> until the execution finishes. To make sure all frameworks have completed, you can use <em>wait_for_all()</em> method to block the program until all tasks finish. </p><div class="fragment"><div class="line"><span class="comment">// Declare a taskflow object</span></div><div class="line"><a class="code" href="classtf_1_1BasicTaskflow.html">tf::Taskflow</a> taskflow;</div><div class="line"></div><div class="line"><span class="comment">// Create a framework whose lifetime is restricted by the scope</span></div><div class="line">{</div><div class="line"> <a class="code" href="classtf_1_1Framework.html">tf::Framework</a> f;</div><div class="line"> </div><div class="line"> <span class="comment">// Add tasks into the framework </span></div><div class="line"> <span class="comment">// ... </span></div><div class="line"></div><div class="line"> <span class="comment">// Dispatch the framework</span></div><div class="line"> taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#af8ebf13bc439f87077c663a3c1008eea">run</a>(f);</div><div class="line"></div><div class="line"> <span class="comment">// Destroy the framework without waiting for execution finishes will lead to undefined behavior</span></div><div class="line">}</div></div><!-- fragment --><h1><a class="anchor" id="C7_CreateAppicationFramework"></a>
Create an Application Framework</h1>
<p>A useful feature of framework is that you can customize your own application framework by inheriting the <a class="el" href="classtf_1_1Framework.html">tf::Framework</a> class. By deriving from the <a class="el" href="classtf_1_1Framework.html">tf::Framework</a>, you can use the same task creation APIs to build the task dependency graph for your own application and utilize the <em>run</em> methods to execute your framework. Below is an example of creating a custom framework</p>
<div class="fragment"><div class="line"><span class="comment">// Define a framework for your application</span></div><div class="line"><span class="keyword">class </span>Foo: <span class="keyword">public</span> <a class="code" href="classtf_1_1Framework.html">tf::Framework</a> {</div><div class="line"> <span class="comment">// Define members data and functions</span></div><div class="line"> <a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/container/vector.html">std::vector<float></a> inputs;</div><div class="line"> <span class="keywordtype">void</span> set_inputs(<a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/container/vector.html">std::vector<float></a>&);</div><div class="line"> <span class="comment">// ...</span></div><div class="line">};</div><div class="line"></div><div class="line"><span class="keywordtype">int</span> main() {</div><div class="line"> <span class="comment">// Declare a taskflow object</span></div><div class="line"> <a class="code" href="classtf_1_1BasicTaskflow.html">tf::Taskflow</a> taskflow;</div><div class="line"></div><div class="line"> <span class="comment">// Declare an application framework</span></div><div class="line"> Foo foo;</div><div class="line"></div><div class="line"> <span class="comment">// Use the task creation APIs to build the task dependency graph in application framework </span></div><div class="line"> <span class="keyword">auto</span> taskA = foo.silent_emplace([](){ <a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <span class="stringliteral">"TaskA\n"</span>; });</div><div class="line"> <span class="keyword">auto</span> taskB = foo.silent_emplace([](){ <a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <span class="stringliteral">"TaskB\n"</span>; });</div><div class="line"> taskA.precede(taskB); </div><div class="line"> <span class="comment">// ...</span></div><div class="line"></div><div class="line"> <span class="comment">// Dispatch your application framework</span></div><div class="line"> taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#acae12080c60f087421317c7681c06f0c">silent_run</a>(foo);</div><div class="line"></div><div class="line"> taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a37ef86998f23ee7315be032c40fe815e">wait_for_all</a>();</div><div class="line">}</div></div><!-- fragment --><h1><a class="anchor" id="C7_Caveats"></a>
Caveats</h1>
<p>Although the framework feature enables task dependency graph reuse, there are few pitfalls need to be aware of</p>
<ul>
<li>Modifying a running framework could result in undefined behavior <div class="fragment"><div class="line"><a class="code" href="classtf_1_1Framework.html">tf::Framework</a> f;</div><div class="line"></div><div class="line"><span class="comment">// Add tasks into the framework </span></div><div class="line"><span class="comment">// ...</span></div><div class="line"></div><div class="line"><span class="comment">// Declare a taskflow object</span></div><div class="line"><a class="code" href="classtf_1_1BasicTaskflow.html">tf::Taskflow</a> taskflow;</div><div class="line"></div><div class="line"><span class="keyword">auto</span> future = taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#af8ebf13bc439f87077c663a3c1008eea">run</a>(f);</div><div class="line"></div><div class="line"><span class="comment">// Modify the framework before the execution finishes leads to undefined behavior </span></div><div class="line">f.<a class="code" href="classtf_1_1FlowBuilder.html#a7285613836c840e22b8511d447734c87">silent_emplace</a>([](){ <a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <span class="stringliteral">"Add a new task\n"</span>; });</div><div class="line"></div><div class="line"><span class="comment">// Use get method to wait for the execution completes.</span></div><div class="line">future.get();</div></div><!-- fragment --></li>
</ul>
<ul>
<li>Continuously run a framework <b>without</b> modification is OK and the result is equivalent to repeating the execution <div class="fragment"><div class="line"><a class="code" href="classtf_1_1Framework.html">tf::Framework</a> f;</div><div class="line"></div><div class="line"><span class="comment">// Add tasks into the framework </span></div><div class="line"><span class="comment">// ...</span></div><div class="line"></div><div class="line"><span class="comment">// Declare a taskflow object</span></div><div class="line"><a class="code" href="classtf_1_1BasicTaskflow.html">tf::Taskflow</a> taskflow;</div><div class="line"></div><div class="line"><span class="comment">// Below is equivalent to: taskflow.silent_run_n(f, 5)</span></div><div class="line">taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a8276dc863390e0f3e0bc53f5cf357338">silent_run_n</a>(f, 2);</div><div class="line">taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a8276dc863390e0f3e0bc53f5cf357338">silent_run_n</a>(f, 3);</div><div class="line"></div><div class="line">taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a37ef86998f23ee7315be032c40fe815e">wait_for_all</a>();</div></div><!-- fragment --></li>
</ul>
<ul>
<li>Subgraphs spawn from dynamic tasking will be removed after each execution. Below code shows the effect of repeating a framework with dynamic tasking. <div class="fragment"><div class="line"><a class="code" href="classtf_1_1Framework.html">tf::Framework</a> f;</div><div class="line"></div><div class="line"><span class="keyword">auto</span> A = f.<a class="code" href="classtf_1_1FlowBuilder.html#a7285613836c840e22b8511d447734c87">silent_emplace</a>([](){ <a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <span class="stringliteral">"TaskA"</span> << std::endl; });</div><div class="line"><span class="keyword">auto</span> B = f.<a class="code" href="classtf_1_1FlowBuilder.html#a7285613836c840e22b8511d447734c87">silent_emplace</a>([](<span class="keyword">auto</span> &subflow){ </div><div class="line"> <a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <span class="stringliteral">"TaskB"</span> << std::endl; </div><div class="line"> subflow.<a class="code" href="classtf_1_1FlowBuilder.html#a7285613836c840e22b8511d447734c87">silent_emplace</a>([](){ <a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <span class="stringliteral">"SubTask"</span> << std::endl; });</div><div class="line">});</div><div class="line">A.precede(B);</div><div class="line"></div><div class="line"><span class="comment">// Declare a taskflow object</span></div><div class="line"><a class="code" href="classtf_1_1BasicTaskflow.html">tf::Taskflow</a> taskflow;</div><div class="line"></div><div class="line"><a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <span class="stringliteral">"First run:"</span> << std::endl;</div><div class="line">taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#af8ebf13bc439f87077c663a3c1008eea">run</a>(f).get();</div><div class="line"><a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << std::endl;</div><div class="line"></div><div class="line"><span class="comment">// Previous spawn subflow is removed before the second execution, only one SubTask message will be printed.</span></div><div class="line"><a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <span class="stringliteral">"Second run:"</span> << std::endl;</div><div class="line">taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#af8ebf13bc439f87077c663a3c1008eea">run</a>(f).get();</div><div class="line"><a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/docs/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << std::endl;</div></div><!-- fragment --> The output: <div class="fragment"><div class="line">First run:</div><div class="line">TaskA</div><div class="line">TaskB </div><div class="line">SubTask </div><div class="line"></div><div class="line">Second run:</div><div class="line">TaskA</div><div class="line">TaskB </div><div class="line">SubTask </div></div><!-- fragment --> </li>
</ul>
</div></div><!-- contents -->
</div><!-- doc-content -->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
<li class="footer">Generated by
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.8.13 </li>
</ul>
</div>
</body>
</html>