forked from taskflow/taskflow
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchapter7.html
More file actions
171 lines (169 loc) · 30.9 KB
/
Copy pathchapter7.html
File metadata and controls
171 lines (169 loc) · 30.9 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
<!-- 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.3.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>In many situations, you will need to execute a task dependency graph multiple times or create a <em>composable</em> graph. <a class="el" href="classtf_1_1Framework.html" title="A reusable task dependency graph. ">tf::Framework</a> is designed for this purpose. This chapter introduces the concept of a framework and shows its usage.</p>
<h1><a class="anchor" id="C7_CreateAFramework"></a>
Create a Framework</h1>
<p>The <a class="el" href="classtf_1_1Framework.html" title="A reusable task dependency graph. ">tf::Framework</a> inherits <a class="el" href="classtf_1_1FlowBuilder.html" title="Building blocks of a task dependency graph. ">tf::FlowBuilder</a> and contains a task dependency graph that is independent of a taskflow object. Executing a framework from a taskflow does not make the graph vanish. You can reuse a framework multiple times. The following example demonstrates how to create a framework.</p>
<div class="fragment"><div class="line"><span class="comment">// create a framework </span></div><div class="line"><a class="code" href="classtf_1_1Framework.html">tf::Framework</a> framework;</div><div class="line"></div><div class="line"><span class="comment">// create three tasks in the framework</span></div><div class="line"><a class="code" href="classtf_1_1Task.html">tf::Task</a> A = framework.<a class="code" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([](){ std::cout << <span class="stringliteral">"This is TaskA\n"</span>; });</div><div class="line"><a class="code" href="classtf_1_1Task.html">tf::Task</a> B = framework.<a class="code" href="classtf_1_1FlowBuilder.html#acab0b4ac82260f47fdb36a3244ee3aaf">placeholder</a>();</div><div class="line"></div><div class="line"><span class="comment">// add a dependency link from A to B</span></div><div class="line">A.<a class="code" href="classtf_1_1Task.html#a8c78c453295a553c1c016e4062da8588">precede</a>(B); </div></div><!-- fragment --><p>Each framework represents a unique task dependency graph. Connecting tasks from different frameworks results in undefined behavior and should be avoided.</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"><a class="code" href="classtf_1_1Framework.html">tf::Framework</a> f1, f2;</div><div class="line"></div><div class="line"><a class="code" href="classtf_1_1Task.html">tf::Task</a> A = f1.<a class="code" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([] () { std::cout << <span class="stringliteral">"task of framework 1\n"</span>; });</div><div class="line"><a class="code" href="classtf_1_1Task.html">tf::Task</a> B = f2.<a class="code" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([] () { std::cout << <span class="stringliteral">"task of framework 2\n"</span>; });</div><div class="line"></div><div class="line"><span class="comment">// connecting tasks from different frameworks results in undefined behaviors</span></div><div class="line">A.<a class="code" href="classtf_1_1Task.html#a8c78c453295a553c1c016e4062da8588">precede</a>(B);</div><div class="line">taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#afc7f9ac974ee803b2d3b5577a6c8a2bc">run</a>(f1);</div></div><!-- fragment --><h1><a class="anchor" id="C7_ExecuteAFramework"></a>
Execute a Framework</h1>
<p>You use one of following methods: <a class="el" href="classtf_1_1BasicTaskflow.html#afc7f9ac974ee803b2d3b5577a6c8a2bc" title="runs the framework once ">tf::Taskflow::run</a>, <a class="el" href="classtf_1_1BasicTaskflow.html#abe9f7964777c2d65052b2dda7307efb6" title="runs the framework for N times ">tf::Taskflow::run_n</a>, or <a class="el" href="classtf_1_1BasicTaskflow.html#a3a24f26ead77969d133d72372df456e0" title="runs the framework multiple times until the predicate becomes true and invoke a callback ...">tf::Taskflow::run_until</a> to run a framework for one time, multiple times, or until a given condition is met. All methods accept an optional callback to invoke after the execution completes. The code below shows several ways 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#a4d52a7fe2814b264846a2085e931652c">emplace</a>(</div><div class="line"> 6: [] () { std::cout << <span class="stringliteral">"This is TaskA\n"</span>; },</div><div class="line"> 7: [] () { std::cout << <span class="stringliteral">"This is TaskB\n"</span>; },</div><div class="line"> 8: [] () { std::cout << <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.<a class="code" href="classtf_1_1Task.html#a8c78c453295a553c1c016e4062da8588">precede</a>(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#afc7f9ac974ee803b2d3b5577a6c8a2bc">run</a>(f);</div><div class="line">18: fu.get();</div><div class="line">19: taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#afc7f9ac974ee803b2d3b5577a6c8a2bc">run</a>(f, [](){ std::cout << <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#abe9f7964777c2d65052b2dda7307efb6">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#abe9f7964777c2d65052b2dda7307efb6">run_n</a>(f, 4, [](){ std::cout << <span class="stringliteral">"end of four executions\n"</span>; }).<span class="keyword">get</span>();</div><div class="line">25:</div><div class="line">26: taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a3a24f26ead77969d133d72372df456e0">run_until</a>(f, [<span class="keywordtype">int</span> cnt=0] () <span class="keyword">mutable</span> { <span class="keywordflow">return</span> (++cnt == 10); });</div></div><!-- fragment --><p>Debrief:</p>
<ul>
<li>Line 1-12 creates a framework of three tasks A, B, and C </li>
<li>Line 15 creates a taskflow object </li>
<li>Line 17-18 runs the framework once and use std::shared_future::get to wait for completion </li>
<li>Line 19 runs the framework once with a callback to invoke when the execution finishes </li>
<li>Line 21-22 runs the framework four times and use <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> to wait for completion </li>
<li>Line 24 runs the framework four times and invokes a callback at the end of the forth execution </li>
<li>Line 26 keeps running the framework until the <code>cnt</code> variable becomes 10</li>
</ul>
<p>Each framework has its own task dependency graph. You should ensure each framework is run by only one taskflow at one time.</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">// Running a framework on two taskflows at the same time gives undefined behavior</span></div><div class="line">5: <a class="code" href="classtf_1_1BasicTaskflow.html">tf::Taskflow</a> taskflow1, taskflow2;</div><div class="line">6: taskflow1.<a class="code" href="classtf_1_1BasicTaskflow.html#afc7f9ac974ee803b2d3b5577a6c8a2bc">run</a>(f);</div><div class="line">7: taskflow2.<a class="code" href="classtf_1_1BasicTaskflow.html#afc7f9ac974ee803b2d3b5577a6c8a2bc">run</a>(f);</div></div><!-- fragment --><p>Multiple runs on a framework from a taskflow will be automatically <em>synchronized</em>. The following example sequentially creates three topologies that run a framework for one, ten, and one times, respectively.</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">// Running a framework on two taskflows at the same time gives undefined behavior</span></div><div class="line">5: <a class="code" href="classtf_1_1BasicTaskflow.html">tf::Taskflow</a> taskflow;</div><div class="line">6: taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#afc7f9ac974ee803b2d3b5577a6c8a2bc">run</a>(f); </div><div class="line">7: taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#abe9f7964777c2d65052b2dda7307efb6">run_n</a>(f, 10);</div><div class="line">8: taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#afc7f9ac974ee803b2d3b5577a6c8a2bc">run</a>(f);</div><div class="line">9: taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#a37ef86998f23ee7315be032c40fe815e">wait_for_all</a>();</div></div><!-- fragment --><h1><a class="anchor" id="C7_VisualizeAFramework"></a>
Visualize a Framework</h1>
<p>Similar to a task, you can name a framework and dump it to a DOT format.</p>
<div class="fragment"><div class="line"> 1: <a class="code" href="classtf_1_1BasicTaskflow.html">tf::Taskflow</a> tf;</div><div class="line"> 2:</div><div class="line"> 3: <span class="comment">// create a framework</span></div><div class="line"> 4: <a class="code" href="classtf_1_1Framework.html">tf::Framework</a> f;</div><div class="line"> 5:</div><div class="line"> 6: <span class="comment">// name the framework</span></div><div class="line"> 7: f.<a class="code" href="classtf_1_1Framework.html#abd711d67b9efc5b09458f047f5fb73c6">name</a>(<span class="stringliteral">"Demo"</span>);</div><div class="line"> 8:</div><div class="line"> 9: <span class="keyword">auto</span> A = f.<a class="code" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([&](){ std::cout << <span class="stringliteral">"TaskA\n"</span>; }).name(<span class="stringliteral">"A"</span>);</div><div class="line">10: <span class="keyword">auto</span> B = f.<a class="code" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([&](<span class="keyword">auto</span>& subflow){</div><div class="line">11: std::cout << <span class="stringliteral">"TaskB\n"</span>;</div><div class="line">12: <span class="keyword">auto</span> B1 = subflow.<a class="code" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([&](){ std::cout << <span class="stringliteral">"TaskB1\n"</span>; }).name(<span class="stringliteral">"B1"</span>);</div><div class="line">13: <span class="keyword">auto</span> B2 = subflow.<a class="code" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([&](){ std::cout << <span class="stringliteral">"TaskB2\n"</span>; }).name(<span class="stringliteral">"B2"</span>);</div><div class="line">14: <span class="keyword">auto</span> B3 = subflow.<a class="code" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([&](){ std::cout << <span class="stringliteral">"TaskB3\n"</span>; }).name(<span class="stringliteral">"B3"</span>);</div><div class="line">15: B1.<a class="code" href="classtf_1_1Task.html#a8c78c453295a553c1c016e4062da8588">precede</a>(B3);</div><div class="line">16: B2.<a class="code" href="classtf_1_1Task.html#a8c78c453295a553c1c016e4062da8588">precede</a>(B3);</div><div class="line">17: }).name(<span class="stringliteral">"B"</span>);</div><div class="line">18:</div><div class="line">19: <span class="keyword">auto</span> C = f.<a class="code" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([&](){ std::cout << <span class="stringliteral">"TaskC\n"</span>; }).name(<span class="stringliteral">"C"</span>);</div><div class="line">20: <span class="keyword">auto</span> D = f.<a class="code" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([&](){ std::cout << <span class="stringliteral">"TaskD\n"</span>; }).name(<span class="stringliteral">"D"</span>);</div><div class="line">21:</div><div class="line">22: A.<a class="code" href="classtf_1_1Task.html#a8c78c453295a553c1c016e4062da8588">precede</a>(B, C);</div><div class="line">23: B.<a class="code" href="classtf_1_1Task.html#a8c78c453295a553c1c016e4062da8588">precede</a>(D);</div><div class="line">24: C.<a class="code" href="classtf_1_1Task.html#a8c78c453295a553c1c016e4062da8588">precede</a>(D);</div><div class="line">25:</div><div class="line">26: <span class="comment">// dump the framework (static portion only)</span></div><div class="line">26: f.<a class="code" href="classtf_1_1Framework.html#a667a978354952ee99f2ef1ae55392083">dump</a>(std::cout);</div></div><!-- fragment --><div class="image">
<img src="framework_static_dump.png" alt="framework_static_dump.png" width="30%"/>
</div>
<p>The framework in this example contains a subflow. You will need to run the framework first to spawn the subflow before you can visualize the dynamic task nodes.</p>
<div class="fragment"><div class="line">1: <span class="comment">// run the framework and make sure it finishes before dump</span></div><div class="line">2: taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#afc7f9ac974ee803b2d3b5577a6c8a2bc">run</a>(f).get();</div><div class="line">3:</div><div class="line">4: <span class="comment">// at this point the subflow graph is spawned</span></div><div class="line">5: f.<a class="code" href="classtf_1_1Framework.html#a667a978354952ee99f2ef1ae55392083">dump</a>(std::cout);</div><div class="line">6:</div><div class="line">7: <span class="comment">// alternatively, you can dump the topology to obtain the same result</span></div><div class="line">8: taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#adac448e1cc44307856b3116d7ed5490f">dump</a>(std::cout);</div></div><!-- fragment --><div class="image">
<img src="framework_dynamic_dump.png" alt="framework_dynamic_dump.png" width="40%"/>
</div>
<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 must remain alive until its execution finishes. It is your responsibility to ensure a framework is not destructed during if it is running. For example, the code below can result undefined behavior.</p>
<div class="fragment"><div class="line"><span class="comment">// create 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">// run the framework</span></div><div class="line"> taskflow.<a class="code" href="classtf_1_1BasicTaskflow.html#afc7f9ac974ee803b2d3b5577a6c8a2bc">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><!-- fragment --><p>Similarly, you should avoid touching a framework while it is running.</p>
<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#afc7f9ac974ee803b2d3b5577a6c8a2bc">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#a4d52a7fe2814b264846a2085e931652c">emplace</a>([](){ std::cout << <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 --><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" title="A reusable task dependency graph. ">tf::Framework</a> class. By deriving from the <a class="el" href="classtf_1_1Framework.html" title="A reusable task dependency graph. ">tf::Framework</a>, you can use the same task creation APIs to build a task dependency graph for your own application and call <code>run_*</code> methods to execute your 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"> std::vector<float> inputs;</div><div class="line"> <span class="keywordtype">void</span> set_inputs(std::vector<float>&);</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"> <a class="code" href="classtf_1_1Task.html">tf::Task</a> taskA = foo.emplace([](){ std::cout << <span class="stringliteral">"TaskA\n"</span>; });</div><div class="line"> <a class="code" href="classtf_1_1Task.html">tf::Task</a> taskB = foo.emplace([](){ std::cout << <span class="stringliteral">"TaskB\n"</span>; });</div><div class="line"> taskA.<a class="code" href="classtf_1_1Task.html#a8c78c453295a553c1c016e4062da8588">precede</a>(taskB); </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#afc7f9ac974ee803b2d3b5577a6c8a2bc">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 class="line"> <span class="keywordflow">return</span> 0;</div><div class="line">}</div></div><!-- fragment --><h1><a class="anchor" id="C7_FrameworkComposition"></a>
Framework Composition</h1>
<p>A powerful feature of <a class="el" href="classtf_1_1Framework.html" title="A reusable task dependency graph. ">tf::Framework</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>
<div class="fragment"><div class="line"> 1: <span class="comment">// f1 has three independent tasks</span></div><div class="line"> 2: <a class="code" href="classtf_1_1Framework.html">tf::Framework</a> f1;</div><div class="line"> 3: <span class="keyword">auto</span> [f1A, f1B, f1C] = f1.<a class="code" href="classtf_1_1Framework.html#abd711d67b9efc5b09458f047f5fb73c6">name</a>(<span class="stringliteral">"F1"</span>).emplace(</div><div class="line"> 4: [&](){ std::cout << <span class="stringliteral">"F1 TaskA\n"</span>; },</div><div class="line"> 5: [&](){ std::cout << <span class="stringliteral">"F1 TaskB\n"</span>; },</div><div class="line"> 6: [&](){ std::cout << <span class="stringliteral">"F1 TaskC\n"</span>; }</div><div class="line"> 7: );</div><div class="line"> 8: f1A.name(<span class="stringliteral">"f1A"</span>);</div><div class="line"> 9: f1B.name(<span class="stringliteral">"f1B"</span>);</div><div class="line">10: f1C.name(<span class="stringliteral">"f1C"</span>);</div><div class="line">11: f1A.precede(f1C);</div><div class="line">12: f1B.precede(f1C);</div><div class="line">13:</div><div class="line">14: <span class="comment">// f2A ---</span></div><div class="line">15: <span class="comment">// |----> f2C ----> f1_module_task ----> f2D</span></div><div class="line">16: <span class="comment">// f2B --- </span></div><div class="line">17: <a class="code" href="classtf_1_1Framework.html">tf::Framework</a> f2;</div><div class="line">18: <span class="keyword">auto</span> [f2A, f2B, f2C, f2D] = f2.<a class="code" href="classtf_1_1Framework.html#abd711d67b9efc5b09458f047f5fb73c6">name</a>(<span class="stringliteral">"F2"</span>).emplace(</div><div class="line">19: [&](){ std::cout << <span class="stringliteral">" F2 TaskA\n"</span>; },</div><div class="line">20: [&](){ std::cout << <span class="stringliteral">" F2 TaskB\n"</span>; },</div><div class="line">21: [&](){ std::cout << <span class="stringliteral">" F2 TaskC\n"</span>; },</div><div class="line">22: [&](){ std::cout << <span class="stringliteral">" F2 TaskD\n"</span>; }</div><div class="line">23: );</div><div class="line">24: f2A.name(<span class="stringliteral">"f2A"</span>);</div><div class="line">25: f2B.name(<span class="stringliteral">"f2B"</span>);</div><div class="line">26: f2C.name(<span class="stringliteral">"f2C"</span>);</div><div class="line">27: f2C.name(<span class="stringliteral">"f2D"</span>);</div><div class="line">28:</div><div class="line">29: f2A.precede(f2C);</div><div class="line">30: f2B.precede(f2C);</div><div class="line">31:</div><div class="line">32: <span class="keyword">auto</span> f1_module_task = f2.<a class="code" href="classtf_1_1Framework.html#acf31b1f085cca58fe87dcfc0eb7fb6ac">composed_of</a>(f1).<a class="code" href="classtf_1_1Task.html#a08ada0425b490997b6ff7f310107e5e3">name</a>(<span class="stringliteral">"module"</span>);</div><div class="line">33: f2C.precede(f1_module_task);</div><div class="line">34: f1_module_task.precede(f2D);</div><div class="line">35:</div><div class="line">36: f2.<a class="code" href="classtf_1_1Framework.html#a667a978354952ee99f2ef1ae55392083">dump</a>(std::cout);</div><div class="line">37:</div><div class="line">38: tf.<a class="code" href="classtf_1_1BasicTaskflow.html#abe9f7964777c2d65052b2dda7307efb6">run_n</a>(f2, 3).get();</div></div><!-- fragment --><div class="image">
<img src="composition_static_1.png" alt="composition_static_1.png" width="37%"/>
</div>
<p>Debrief:</p>
<ul>
<li>Line 1-12 creates a framework of three tasks f1A, f1B, and f1C with f1A and f1B preceding f1C </li>
<li>Line 17-30 creates a framework of four tasks f2A, f2B, f2C, and f2D </li>
<li>Line 32 creates a module task from framework f1 through the method <a class="el" href="classtf_1_1Framework.html#acf31b1f085cca58fe87dcfc0eb7fb6ac" title="creates a module task from a framework ">Framework::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 <a class="el" href="classtf_1_1Framework.html#acf31b1f085cca58fe87dcfc0eb7fb6ac" title="creates a module task from a framework ">Framework::composed_of</a> is a <em>module</em> task that runs on a framework. A module task does not owns any framework but maintains a soft mapping to use during its execution context. You can create multiple module tasks from the same framework 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 framework <code>F1</code>, the dependency link prevents <code>F1</code> from multiple executions at the same time.</p>
<div class="image">
<img src="composition_static_2.png" alt="composition_static_2.png" width="37%"/>
</div>
<p>However, the following composition is <em>invalid</em>. Both module tasks refer to the same framework. They can not run at the same time because they are associated with the same graph.</p>
<div class="image">
<img src="composition_static_invalid.png" alt="composition_static_invalid.png" width="50%"/>
</div>
<h1><a class="anchor" id="C7_Caveats"></a>
Caveats</h1>
<p>Although <a class="el" href="classtf_1_1Framework.html" title="A reusable task dependency graph. ">tf::Framework</a> enables efficient reuse of a task dependency graph, there can be many potential pitfalls. We are still experimenting <a class="el" href="classtf_1_1Framework.html" title="A reusable task dependency graph. ">tf::Framework</a> to develop a safe interface. Please stay tuned with <a class="el" href="master-branch.html">Master Branch (GitHub)</a>. </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>