forked from taskflow/taskflow
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathchapter2.html
More file actions
175 lines (173 loc) · 35.2 KB
/
chapter2.html
File metadata and controls
175 lines (173 loc) · 35.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
<!-- 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('chapter2.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">C2: Dispatch a Task Dependency Graph </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>After you create a task dependency graph, you need to dispatch it to threads for execution. In this chapter, we will show you how to execute a task dependency graph.</p>
<h1><a class="anchor" id="GraphAndTopology"></a>
Graph and Topology</h1>
<p>Each taskflow object has exactly one graph at a time that represents the tasks and the dependencies constructed so far. The graph exists until users dispatch it for execution. In Cpp-Taskflow, we call a dispatched graph a <em>topology</em>. A topology is a data structure that wraps up a dispatched graph and stores a few metadata obtained at runtime. Each taskflow object has a list of topologies to keep track of the execution status of dispatched graphs. Users can retrieve this information later on for graph inspection and debugging.</p>
<p>All tasks are executed in a shared thread storage coupled with a <em>task scheduler</em> to decide which thread runs which task. Cpp-Taskflow provides two ways to dispatch a task dependency graph, <em>blocking</em> and <em>non-blocking</em> executions.</p>
<h1><a class="anchor" id="BlockingExecution"></a>
Blocking Execution</h1>
<p>One way to dispatch the present task dependency graph is to use the method <a class="el" href="classtf_1_1BasicTaskflow.html#a37ef86998f23ee7315be032c40fe815e" title="dispatches the present graph to threads and wait for all topologies to complete ">tf::Taskflow::wait_for_all</a>. Calling <code>wait_for_all</code> dispatches the graph to threads and blocks the program flow until all tasks finish.</p>
<div class="fragment"><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> A = taskflow.<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\n"</span>; });</div><div class="line"><span class="keyword">auto</span> B = taskflow.<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">"TaskB\n"</span>; });</div><div class="line">A.precede(B);</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 --><p>When <code>wait_for_all</code> returns, all tasks including previously dispatched ones are guaranteed to finish. All topologies will be cleaned up as well.</p>
<h1><a class="anchor" id="NonBlockingExecution"></a>
Non-blocking Execution</h1>
<p>Another way to dispatch the present task dependency graph is to use the method <a class="el" href="classtf_1_1BasicTaskflow.html#a848e425f67b49a8a7ac21f6b791999c5" title="dispatches the present graph to threads and returns immediately ">tf::Taskflow::dispatch</a> or <a class="el" href="classtf_1_1BasicTaskflow.html#a0126001a2bd8603af4827049578629cb" title="dispatches the present graph to threads and returns immediately ">tf::Taskflow::silent_dispatch</a>. These two methods both dispatch the present graph to threads and return immediately without blocking the program flow. Non-blocking methods allow the program to perform other computations that can overlap the graph execution.</p>
<div class="fragment"><div class="line"> 1: <a class="code" href="classtf_1_1BasicTaskflow.html">tf::Taskflow</a> taskflow;</div><div class="line"> 2:</div><div class="line"> 3: <span class="keyword">auto</span> A = taskflow.<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">"Task A\n"</span>; });</div><div class="line"> 4: <span class="keyword">auto</span> B = taskflow.<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">"Task B\n"</span>; });</div><div class="line"> 5: A.precede(B);</div><div class="line"> 6:</div><div class="line"> 7: <span class="keyword">auto</span> F = taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a848e425f67b49a8a7ac21f6b791999c5">dispatch</a>();</div><div class="line"> 8: <span class="comment">// do some computation to overlap the execution of tasks A and B</span></div><div class="line"> 9: <span class="comment">// ...</span></div><div class="line">10: F.get();</div></div><!-- fragment --><p>Debrief:</p>
<ul>
<li>Line 1-5 creates a graph with two tasks and one dependency </li>
<li>Line 7 dispatches this graph </li>
<li>and obtains 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 to access its execution status </li>
<li>Line 8-9 performs some computations to overlap the execution of task A and task B </li>
<li>Line 10 blocks the program until this topology finishes</li>
</ul>
<p>The method <code>dispatch</code> has a overload that takes a callable object to execute when the dispatched graph finishes.</p>
<div class="fragment"><div class="line"><a class="code" href="classtf_1_1BasicTaskflow.html">tf::Taskflow</a> taskflow;</div><div class="line"><span class="keywordtype">int</span> counter {0};</div><div class="line"><span class="keyword">auto</span> A = taskflow.<a class="code" href="classtf_1_1FlowBuilder.html#a7285613836c840e22b8511d447734c87">silent_emplace</a>([&] () { counter++; });</div><div class="line">taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a848e425f67b49a8a7ac21f6b791999c5">dispatch</a>([&] () { assert(counter == 1); })</div></div><!-- fragment --><p>If you do not care the status of a dispatched graph, use the method <a class="el" href="classtf_1_1BasicTaskflow.html#a0126001a2bd8603af4827049578629cb" title="dispatches the present graph to threads and returns immediately ">tf::Taskflow::silent_dispatch</a>. This method does not return anything.</p>
<div class="fragment"><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> A = taskflow.<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\n"</span>; });</div><div class="line"><span class="keyword">auto</span> B = taskflow.<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">"TaskB\n"</span>; });</div><div class="line">A.precede(B);</div><div class="line"></div><div class="line"><span class="keyword">auto</span> F = taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a848e425f67b49a8a7ac21f6b791999c5">dispatch</a>();</div><div class="line"><span class="comment">// do some computation to overlap the execution of tasks A and B</span></div><div class="line"><span class="comment">// ...</span></div></div><!-- fragment --><p>Similarly, the method <code>silent_dispatch</code> has an overload that takes a callable object to execute when the dispatched graph finishes.</p>
<div class="fragment"><div class="line"><a class="code" href="classtf_1_1BasicTaskflow.html">tf::Taskflow</a> taskflow;</div><div class="line"><span class="keywordtype">int</span> counter {0};</div><div class="line"><span class="keyword">auto</span> A = taskflow.<a class="code" href="classtf_1_1FlowBuilder.html#a7285613836c840e22b8511d447734c87">silent_emplace</a>([&] () { counter++; });</div><div class="line">taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a0126001a2bd8603af4827049578629cb">silent_dispatch</a>([&] () { assert(counter == 1); })</div></div><!-- fragment --><h1><a class="anchor" id="WaitForTopologies"></a>
Wait for Topologies</h1>
<p>Unlike <a class="el" href="classtf_1_1BasicTaskflow.html#a37ef86998f23ee7315be032c40fe815e" title="dispatches the present graph to threads and wait for all topologies to complete ">tf::Taskflow::wait_for_all</a>, calling <a class="el" href="classtf_1_1BasicTaskflow.html#a848e425f67b49a8a7ac21f6b791999c5" title="dispatches the present graph to threads and returns immediately ">tf::Taskflow::dispatch</a> or <a class="el" href="classtf_1_1BasicTaskflow.html#a0126001a2bd8603af4827049578629cb" title="dispatches the present graph to threads and returns immediately ">tf::Taskflow::silent_dispatch</a> will not clean up the topologies upon completion. This allows users to dump the graph structure, in particular, created from dynamic tasking to debug the dependency graph. However, it may be necessary at some points of the program to synchronize with the previously dispatched graphs. Cpp-Taskflow provides a method <a class="el" href="classtf_1_1BasicTaskflow.html#a8f0ce2026118e97b83cbd727ed0932af" title="blocks until all running topologies complete and then cleans up all associated storages ...">tf::Taskflow::wait_for_topologies</a> for this purpose.</p>
<div class="fragment"><div class="line"> 1: <a class="code" href="classtf_1_1BasicTaskflow.html">tf::Taskflow</a> taskflow(4);</div><div class="line"> 2: </div><div class="line"> 3: <span class="keyword">auto</span> A = taskflow.<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\n"</span>; });</div><div class="line"> 4: <span class="keyword">auto</span> B = taskflow.<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">"TaskB\n"</span>; });</div><div class="line"> 5: A.precede(B);</div><div class="line"> 6:</div><div class="line"> 7: <span class="keyword">auto</span> F = taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a848e425f67b49a8a7ac21f6b791999c5">dispatch</a>(); <span class="comment">// dispatch the present graph</span></div><div class="line"> 8:</div><div class="line"> 9: <span class="keyword">auto</span> C = taskflow.<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">"TaskC\n"</span>; });</div><div class="line">10:</div><div class="line">11: taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a0126001a2bd8603af4827049578629cb">silent_dispatch</a>(); <span class="comment">// dispatch the present graph</span></div><div class="line">12:</div><div class="line">13: taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a8f0ce2026118e97b83cbd727ed0932af">wait_for_topologies</a>(); <span class="comment">// block until the two graphs finish</span></div><div class="line">14: </div><div class="line">15: assert(F.wait_for(<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/chrono/duration.html">std::chrono::seconds</a>(0)) == std::future_status::ready);</div></div><!-- fragment --><p>Debrief </p><ul>
<li>Line 1 creates a taskflow object with four worker threads </li>
<li>Line 3-5 creates a dependency graph of two tasks and one dependency </li>
<li>Line 7 dispatches this graph to threads and obtains 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 for users to access the execution status </li>
<li>Line 9 starts with a new dependency graph with one task </li>
<li>Line 11 dispatches the graph to threads </li>
<li>Line 13 blocks the program until both graphs finish</li>
</ul>
<p>It is clear now Line 9 overlaps the execution of the first graph. After Line 11, there are two topologies in the taskflow object. Calling the method <a class="el" href="classtf_1_1BasicTaskflow.html#a8f0ce2026118e97b83cbd727ed0932af" title="blocks until all running topologies complete and then cleans up all associated storages ...">tf::Taskflow::wait_for_topologies</a> blocks the program until both graph complete.</p>
<h1><a class="anchor" id="LifeTimeOfAGraph"></a>
Lifetime of a Graph</h1>
<p>In Cpp-Taskflow, the lifetime of a task sticks with its parent graph. The lifetime of a task mostly refers to the user-given callable objects, including those captured by a lambda expression. When a graph is destroyed, all of its tasks are destroyed. Consider the following example that uses <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/memory/shared_ptr.html">std::shared_ptr</a> to demonstrate the lifetime of a graph and the impact on its task.</p>
<div class="fragment"><div class="line"> 1: <a class="code" href="classtf_1_1BasicTaskflow.html">tf::Taskflow</a> taskflow;</div><div class="line"> 2:</div><div class="line"> 3: <span class="keyword">auto</span> ptr = std::make_shared<int>(0);</div><div class="line"> 4:</div><div class="line"> 5: <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">"reference count before A and B: "</span> << ptr.use_count() << <span class="charliteral">'\n'</span>;</div><div class="line"> 6:</div><div class="line"> 7: <span class="keyword">auto</span> A = taskflow.<a class="code" href="classtf_1_1FlowBuilder.html#a7285613836c840e22b8511d447734c87">silent_emplace</a>([ptr] () {</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">"reference count at A: "</span> << ptr.use_count() << <span class="charliteral">'\n'</span>;</div><div class="line"> 9: });</div><div class="line">10:</div><div class="line">11: <span class="keyword">auto</span> B = taskflow.<a class="code" href="classtf_1_1FlowBuilder.html#a7285613836c840e22b8511d447734c87">silent_emplace</a>([ptr] () {</div><div class="line">12: <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">"reference count at B: "</span> << ptr.use_count() << <span class="charliteral">'\n'</span>;</div><div class="line">13: });</div><div class="line">14:</div><div class="line">15: A.precede(B);</div><div class="line">16:</div><div class="line">17: <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">"reference count after A and B: "</span> << ptr.use_count() << <span class="charliteral">'\n'</span>;</div><div class="line">18:</div><div class="line">19: taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a37ef86998f23ee7315be032c40fe815e">wait_for_all</a>();</div><div class="line">20:</div><div class="line">21: <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">"reference count after A and B: "</span> << ptr.use_count() << <span class="charliteral">'\n'</span>;</div></div><!-- fragment --><p>The output is as follows:</p>
<div class="fragment"><div class="line">reference count before A and B: 1</div><div class="line">reference count after A and B: 3</div><div class="line">reference count at A: 3</div><div class="line">reference count at B: 3</div><div class="line">reference count after A and B: 1</div></div><!-- fragment --><p>In Line 5, we created a shared pointer object with one reference count on itself. After Line 7-13, the reference count increases by two because task A and task B both capture a copy of the shared pointer. The lifetime of a task has nothing to do with its dependency constraints, as shown in Line 8, Line 12, and Line 17. However, Line 19 dispatches the graph to threads and cleans up its data structure upon finish, including all associated tasks. Therefore, the reference count in Line 21 drops down to one (owner at Line 3).</p>
<p>Now let's use the same example but dispatch the graph asynchronously.</p>
<div class="fragment"><div class="line"> 1: <a class="code" href="classtf_1_1BasicTaskflow.html">tf::Taskflow</a> taskflow;</div><div class="line"> 2:</div><div class="line"> 3: <span class="keyword">auto</span> ptr = std::make_shared<int>(0);</div><div class="line"> 4:</div><div class="line"> 5: <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">"reference count before A and B: "</span> << ptr.use_count() << <span class="charliteral">'\n'</span>;</div><div class="line"> 6:</div><div class="line"> 7: <span class="keyword">auto</span> A = taskflow.<a class="code" href="classtf_1_1FlowBuilder.html#a7285613836c840e22b8511d447734c87">silent_emplace</a>([ptr] () {</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">"reference count at A: "</span> << ptr.use_count() << <span class="charliteral">'\n'</span>;</div><div class="line"> 9: });</div><div class="line">10:</div><div class="line">11: <span class="keyword">auto</span> B = taskflow.<a class="code" href="classtf_1_1FlowBuilder.html#a7285613836c840e22b8511d447734c87">silent_emplace</a>([ptr] () {</div><div class="line">12: <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">"reference count at B: "</span> << ptr.use_count() << <span class="charliteral">'\n'</span>;</div><div class="line">13: });</div><div class="line">14:</div><div class="line">15: A.precede(B);</div><div class="line">16:</div><div class="line">17: <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">"reference count after A and B: "</span> << ptr.use_count() << <span class="charliteral">'\n'</span>;</div><div class="line">18:</div><div class="line">19: taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a848e425f67b49a8a7ac21f6b791999c5">dispatch</a>().get(); <span class="comment">// dispatch the graph without destroying it</span></div><div class="line">20:</div><div class="line">21: <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">"reference count after A and B: "</span> << ptr.use_count() << <span class="charliteral">'\n'</span>;</div></div><!-- fragment --><p>In Line 19, we replace <code>wait_for_all</code> with <code>dispatch</code> to dispatch the graph asynchronously without cleaning up its data structures upon completion. In other words, task A and task B remains un-destructed after Line 19, and the reference count at this point remains three.</p>
<div class="fragment"><div class="line">reference count before A and B: 1</div><div class="line">reference count after A and B: 3</div><div class="line">reference count at A: 3</div><div class="line">reference count at B: 3</div><div class="line">reference count after A and B: 3</div></div><!-- fragment --><h1><a class="anchor" id="Chapter2Example1"></a>
Example 1: Multiple Dispatches</h1>
<p>The example below demonstrates how to create multiple task dependency graphs and dispatch each of them asynchronously.</p>
<div class="fragment"><div class="line"> 1: #include <taskflow/taskflow.hpp></div><div class="line"> 2:</div><div class="line"> 3: <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/atomic/atomic.html">std::atomic<int></a> counter {0};</div><div class="line"> 4:</div><div class="line"> 5: <span class="keywordtype">void</span> create_graph(<a class="code" href="classtf_1_1BasicTaskflow.html">tf::Taskflow</a>& <a class="code" href="namespacetf.html">tf</a>) {</div><div class="line"> 6: <span class="keyword">auto</span> [A, B] = taskflow.<a class="code" href="classtf_1_1FlowBuilder.html#a7285613836c840e22b8511d447734c87">silent_emplace</a>(</div><div class="line"> 7: [&] () { counter.fetch_add(1, std::memory_order_relaxed); },</div><div class="line"> 8: [&] () { counter.fetch_add(1, std::memory_order_relaxed); }</div><div class="line"> 9: );</div><div class="line">10: }</div><div class="line">11:</div><div class="line">12: <span class="keywordtype">void</span> multiple_dispatches() {</div><div class="line">13: <a class="code" href="classtf_1_1BasicTaskflow.html">tf::Taskflow</a> taskflow(4);</div><div class="line">14: <span class="keywordflow">for</span>(<span class="keywordtype">int</span> i=0; i<10; ++i) {</div><div class="line">15: <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">"dispatch iteration "</span> << i << <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/manip/endl.html">std::endl</a>;</div><div class="line">16: create_graph(tf);</div><div class="line">17: taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a0126001a2bd8603af4827049578629cb">silent_dispatch</a>();</div><div class="line">18: }</div><div class="line">19: }</div><div class="line">20:</div><div class="line">21: <span class="keywordtype">int</span> main() {</div><div class="line">22:</div><div class="line">23: multiple_dispatches();</div><div class="line">24: assert(counter == 20);</div><div class="line">25:</div><div class="line">26: <span class="keywordflow">return</span> 0;</div><div class="line">27: }</div></div><!-- fragment --><p>Debrief: </p><ul>
<li>Line 3 declares a global atomic variable initialized to zero </li>
<li>Line 5-10 defines a function that takes a taskflow object and creates two tasks to increment the counter </li>
<li>Line 12-19 defines a function that iteratively creates a task dependency graph and dispatches it asynchronously </li>
<li>Line 23 starts the procedure of multiple dispatches</li>
</ul>
<p>Notice in Line 24 the counter ends up being 20. By default, destructing a taskflow object will wait on all topologies to finish.</p>
<h1><a class="anchor" id="Chapter2Example2"></a>
Example 2: Connect Two Dependency Graphs</h1>
<p>The example demonstrates how to use the <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/future.html">std::future</a> to explicitly impose a dependency link on two dispatched graphs.</p>
<div class="fragment"><div class="line"> 1: #include <taskflow/taskflow.hpp></div><div class="line"> 2:</div><div class="line"> 3: <span class="keywordtype">int</span> main() {</div><div class="line"> 4:</div><div class="line"> 5: <a class="code" href="classtf_1_1BasicTaskflow.html">tf::Taskflow</a> taskflow(4);</div><div class="line"> 6:</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/container/vector.html">std::vector<int></a> items; <span class="comment">// uninitialized</span></div><div class="line"> 8: <span class="keywordtype">int</span> sum; <span class="comment">// uninitialized</span></div><div class="line"> 9:</div><div class="line">10: <span class="comment">// the first dependency graph</span></div><div class="line">11: <span class="comment">// task C to resize the item vector</span></div><div class="line">12: <span class="keyword">auto</span> A = taskflow.<a class="code" href="classtf_1_1FlowBuilder.html#a7285613836c840e22b8511d447734c87">silent_emplace</a>([&] () { items.resize(1024); });</div><div class="line">13: </div><div class="line">14: <span class="comment">// task B to initialize the item vector</span></div><div class="line">15: <span class="keyword">auto</span> B = taskflow.<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/algorithm/iota.html">std::iota</a>(items.begin(), items.end(), 0); });</div><div class="line">16:</div><div class="line">17: <span class="comment">// A must run before B</span></div><div class="line">18: A.precede(B);</div><div class="line">19: </div><div class="line">20: <span class="comment">// dispatch the graph asynchronously and obtain the future to access its status</span></div><div class="line">21: <span class="keyword">auto</span> fu1 = taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a848e425f67b49a8a7ac21f6b791999c5">dispatch</a>();</div><div class="line">22:</div><div class="line">23: <span class="comment">// the second dependency graph</span></div><div class="line">24: <span class="comment">// task C to overlap the exeuction of the first graph</span></div><div class="line">25: <span class="keyword">auto</span> C = taskflow.<a class="code" href="classtf_1_1FlowBuilder.html#a7285613836c840e22b8511d447734c87">silent_emplace</a>([&] () {</div><div class="line">26: sum = 0; <span class="comment">// in practice, this can be some expensive initializations</span></div><div class="line">27: });</div><div class="line">28:</div><div class="line">29: <span class="comment">// task D can't start until the first graph completes</span></div><div class="line">30: <span class="keyword">auto</span> D = taskflow.<a class="code" href="classtf_1_1FlowBuilder.html#a7285613836c840e22b8511d447734c87">silent_emplace</a>([&] () {</div><div class="line">31: fu1.get();</div><div class="line">32: <span class="keywordflow">for</span>(<span class="keyword">auto</span> item : items) {</div><div class="line">33: sum += item;</div><div class="line">34: }</div><div class="line">35: });</div><div class="line">36: </div><div class="line">37: C.precede(D);</div><div class="line">38: </div><div class="line">39: <span class="keyword">auto</span> fu2 = taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a848e425f67b49a8a7ac21f6b791999c5">dispatch</a>();</div><div class="line">40: </div><div class="line">41: <span class="comment">// wait on the second dependency graph to finish</span></div><div class="line">42: fu2.get();</div><div class="line">43: </div><div class="line">44: assert(sum == (0 + 1023) * 1024 / 2);</div><div class="line">45: </div><div class="line">46: <span class="keywordflow">return</span> 0;</div><div class="line">47: }</div></div><!-- fragment --><p>Debrief: </p><ul>
<li>Line 5 creates a taskflow object with four worker threads </li>
<li>Line 7-8 creates a vector of integer items and an integer variable to store the summation value </li>
<li>Line 10-21 creates a dependency graph that resizes the vector and fills it with sequentially increasing values starting with zero </li>
<li>Line 23-39 creates another dependency graph that sums up the values in the vector </li>
<li>Line 25-27 creates a task that initializes the variable <code>sum</code> to zero, and overlaps its execution with the first dependency graph </li>
<li>Line 30-35 creates a task that blocks until the first dependency graph completes and then sums up all integer values in the properly initialized vector </li>
<li>Line 42 blocks until the second dependency graph finishes </li>
<li>Line 44 puts an assertion guard on the final summation value</li>
</ul>
<p>By the time the second dependency graph finishes, the first dependency graph must have already finished due to Line 31. The result of the variable <code>sum</code> ends up being the summation over the integer sequence [0, 1, 2, ..., 1024). </p>
</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>