-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Expand file tree
/
Copy pathDataParallelPipeline.html
More file actions
245 lines (243 loc) · 22.6 KB
/
Copy pathDataParallelPipeline.html
File metadata and controls
245 lines (243 loc) · 22.6 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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
<!-- HTML header for doxygen 1.13.1-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
<meta name="generator" content="Doxygen 1.13.1"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Taskflow: A General-purpose Task-parallel Programming System: Data-parallel Pipeline</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<script type="text/javascript" src="clipboard.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="cookie.js"></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>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="custom.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 id="projectrow">
<td id="projectlogo"><img alt="Logo" src="taskflow_logo.png"/></td>
<td id="projectalign">
<div id="projectname"><a href="https://github.com/taskflow/taskflow" style="color:inherit; text-decoration:none;">Taskflow: A General-purpose Task-parallel Programming System</a>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.13.1 -->
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt MIT */
var searchBox = new SearchBox("searchBox", "search/",'.html');
/* @license-end */
</script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt MIT */
$(function() { codefold.init(0); });
/* @license-end */
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt MIT */
$(function() {
initMenu('',true,false,'search.php','Search',true);
$(function() { init_search(); });
});
/* @license-end */
</script>
<div id="main-nav"></div>
</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">
/* @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt MIT */
$(function(){initNavTree('DataParallelPipeline.html',''); initResizable(true); });
/* @license-end */
</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">
<div id="MSearchResults">
<div class="SRPage">
<div id="SRIndex">
<div id="SRResults"></div>
<div class="SRStatus" id="Loading">Loading...</div>
<div class="SRStatus" id="Searching">Searching...</div>
<div class="SRStatus" id="NoMatches">No Matches</div>
</div>
</div>
</div>
</div>
<div><div class="header">
<div class="headertitle"><div class="title">Data-parallel Pipeline</div></div>
</div><!--header-->
<div class="contents">
<div class="toc"><h3>Table of Contents</h3>
<ul>
<li class="level1">
<a href="#ParallelDataPipelineIncludeHeaderFile">Include the Header</a>
</li>
<li class="level1">
<a href="#CreateADataPipelineModuleTask">Create a Data Pipeline Module Task</a>
</li>
<li class="level1">
<a href="#UnderstandInternalDataStorage">Understand Internal Data Storage</a>
</li>
</ul>
</div>
<div class="textblock"><p>Taskflow provides another variant, <a class="el" href="classtf_1_1DataPipeline.html" title="class to create a data-parallel pipeline scheduling framework">tf::DataPipeline</a>, on top of <a class="el" href="classtf_1_1Pipeline.html" title="class to create a pipeline scheduling framework">tf::Pipeline</a> (see <a class="el" href="TaskParallelPipeline.html">Task-parallel Pipeline</a>) to help you implement data-parallel pipeline algorithms while leaving data management to Taskflow. We recommend you finishing reading TaskParallelPipeline first before learning <a class="el" href="classtf_1_1DataPipeline.html" title="class to create a data-parallel pipeline scheduling framework">tf::DataPipeline</a>.</p>
<h1><a class="anchor" id="ParallelDataPipelineIncludeHeaderFile"></a>
Include the Header</h1>
<p>You need to include the header file, <code>taskflow/algorithm/data_pipeline.hpp</code>, for implementing data-parallel pipeline algorithms.</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include <taskflow/algorithm/data_pipeline.hpp></span></div>
</div><!-- fragment --><h1><a class="anchor" id="CreateADataPipelineModuleTask"></a>
Create a Data Pipeline Module Task</h1>
<p>Similar to creating a task-parallel pipeline (<a class="el" href="classtf_1_1Pipeline.html" title="class to create a pipeline scheduling framework">tf::Pipeline</a>), there are three steps to create a data-parallel pipeline application:</p>
<ol type="1">
<li>Define the pipeline structure (e.g., pipe type, pipe callable, stopping rule, line count)</li>
<li>Define the data storage and layout, if needed for the application</li>
<li>Define the pipeline taskflow graph using composition</li>
</ol>
<p>The following example creates a data-parallel pipeline that generates a total of five dataflow tokens from <code>void</code> to <code>int</code> at the first stage, from <code>int</code> to <code>std::string</code> at the second stage, and <code>std::string</code> to <code>void</code> at the final stage. Data storage between stages is automatically managed by <a class="el" href="classtf_1_1DataPipeline.html" title="class to create a data-parallel pipeline scheduling framework">tf::DataPipeline</a>.</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include <taskflow/taskflow.hpp></span></div>
<div class="line"><span class="preprocessor">#include <taskflow/algorithm/data_pipeline.hpp></span></div>
<div class="line"> </div>
<div class="line"><span class="keywordtype">int</span> main() {</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// data flow => void -> int -> std::string -> void </span></div>
<div class="line"> <a class="code hl_class" href="classtf_1_1Taskflow.html">tf::Taskflow</a> taskflow(<span class="stringliteral">"pipeline"</span>);</div>
<div class="line"> <a class="code hl_class" href="classtf_1_1Executor.html">tf::Executor</a> executor;</div>
<div class="line"> </div>
<div class="line"> <span class="keyword">const</span> <span class="keywordtype">size_t</span> num_lines = 4;</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// create a pipeline graph</span></div>
<div class="line"> <a class="code hl_class" href="classtf_1_1DataPipeline.html">tf::DataPipeline</a> pl(num_lines,</div>
<div class="line"> <a class="code hl_function" href="namespacetf.html#a8975fa5762088789adb0b60f38208309">tf::make_data_pipe<void, int></a>(<a class="code hl_enumvalue" href="namespacetf.html#abb7a11e41fd457f69e7ff45d4c769564a7b804a28d6154ab8007287532037f1d0">tf::PipeType::SERIAL</a>, [&](<a class="code hl_class" href="classtf_1_1Pipeflow.html">tf::Pipeflow</a>& pf) -> <span class="keywordtype">int</span>{</div>
<div class="line"> <span class="keywordflow">if</span>(pf.<a class="code hl_function" href="classtf_1_1Pipeflow.html#a295e5d884665c076f4ef5d78139f7c51">token</a>() == 5) {</div>
<div class="line"> pf.<a class="code hl_function" href="classtf_1_1Pipeflow.html#a830b7f204cb87fff17e8d424918d9453">stop</a>();</div>
<div class="line"> <span class="keywordflow">return</span> 0;</div>
<div class="line"> }</div>
<div class="line"> <span class="keywordflow">else</span> {</div>
<div class="line"> printf(<span class="stringliteral">"first pipe returns %lu\n"</span>, pf.<a class="code hl_function" href="classtf_1_1Pipeflow.html#a295e5d884665c076f4ef5d78139f7c51">token</a>());</div>
<div class="line"> <span class="keywordflow">return</span> pf.<a class="code hl_function" href="classtf_1_1Pipeflow.html#a295e5d884665c076f4ef5d78139f7c51">token</a>();</div>
<div class="line"> }</div>
<div class="line"> }),</div>
<div class="line"> </div>
<div class="line"> <a class="code hl_function" href="namespacetf.html#a8975fa5762088789adb0b60f38208309">tf::make_data_pipe<int, std::string></a>(<a class="code hl_enumvalue" href="namespacetf.html#abb7a11e41fd457f69e7ff45d4c769564a7b804a28d6154ab8007287532037f1d0">tf::PipeType::SERIAL</a>, [](<span class="keywordtype">int</span>& input) {</div>
<div class="line"> printf(<span class="stringliteral">"second pipe returns a string of %d\n"</span>, input + 100);</div>
<div class="line"> <span class="keywordflow">return</span> std::to_string(input + 100);</div>
<div class="line"> }),</div>
<div class="line"> </div>
<div class="line"> <a class="code hl_function" href="namespacetf.html#a8975fa5762088789adb0b60f38208309">tf::make_data_pipe<std::string, void></a>(<a class="code hl_enumvalue" href="namespacetf.html#abb7a11e41fd457f69e7ff45d4c769564a7b804a28d6154ab8007287532037f1d0">tf::PipeType::SERIAL</a>, [](std::string& input) {</div>
<div class="line"> printf(<span class="stringliteral">"third pipe receives the input string %s\n"</span>, input.c_str());</div>
<div class="line"> })</div>
<div class="line"> );</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// build the pipeline graph using composition</span></div>
<div class="line"> taskflow.composed_of(pl).name(<span class="stringliteral">"pipeline"</span>);</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// dump the pipeline graph structure (with composition)</span></div>
<div class="line"> taskflow.dump(std::cout);</div>
<div class="line"> </div>
<div class="line"> <span class="comment">// run the pipeline</span></div>
<div class="line"> executor.<a class="code hl_function" href="classtf_1_1Executor.html#a519777f5783981d534e9e53b99712069">run</a>(taskflow).wait();</div>
<div class="line"> </div>
<div class="line"> <span class="keywordflow">return</span> 0;</div>
<div class="line">}</div>
<div class="ttc" id="aclasstf_1_1DataPipeline_html"><div class="ttname"><a href="classtf_1_1DataPipeline.html">tf::DataPipeline</a></div><div class="ttdoc">class to create a data-parallel pipeline scheduling framework</div><div class="ttdef"><b>Definition</b> data_pipeline.hpp:254</div></div>
<div class="ttc" id="aclasstf_1_1Executor_html"><div class="ttname"><a href="classtf_1_1Executor.html">tf::Executor</a></div><div class="ttdoc">class to create an executor</div><div class="ttdef"><b>Definition</b> executor.hpp:62</div></div>
<div class="ttc" id="aclasstf_1_1Executor_html_a519777f5783981d534e9e53b99712069"><div class="ttname"><a href="classtf_1_1Executor.html#a519777f5783981d534e9e53b99712069">tf::Executor::run</a></div><div class="ttdeci">tf::Future< void > run(Taskflow &taskflow)</div><div class="ttdoc">runs a taskflow once</div></div>
<div class="ttc" id="aclasstf_1_1Pipeflow_html"><div class="ttname"><a href="classtf_1_1Pipeflow.html">tf::Pipeflow</a></div><div class="ttdoc">class to create a pipeflow object used by the pipe callable</div><div class="ttdef"><b>Definition</b> pipeline.hpp:43</div></div>
<div class="ttc" id="aclasstf_1_1Pipeflow_html_a295e5d884665c076f4ef5d78139f7c51"><div class="ttname"><a href="classtf_1_1Pipeflow.html#a295e5d884665c076f4ef5d78139f7c51">tf::Pipeflow::token</a></div><div class="ttdeci">size_t token() const</div><div class="ttdoc">queries the token identifier</div><div class="ttdef"><b>Definition</b> pipeline.hpp:78</div></div>
<div class="ttc" id="aclasstf_1_1Pipeflow_html_a830b7f204cb87fff17e8d424918d9453"><div class="ttname"><a href="classtf_1_1Pipeflow.html#a830b7f204cb87fff17e8d424918d9453">tf::Pipeflow::stop</a></div><div class="ttdeci">void stop()</div><div class="ttdoc">stops the pipeline scheduling</div><div class="ttdef"><b>Definition</b> pipeline.hpp:88</div></div>
<div class="ttc" id="aclasstf_1_1Taskflow_html"><div class="ttname"><a href="classtf_1_1Taskflow.html">tf::Taskflow</a></div><div class="ttdoc">class to create a taskflow object</div><div class="ttdef"><b>Definition</b> taskflow.hpp:64</div></div>
<div class="ttc" id="anamespacetf_html_a8975fa5762088789adb0b60f38208309"><div class="ttname"><a href="namespacetf.html#a8975fa5762088789adb0b60f38208309">tf::make_data_pipe</a></div><div class="ttdeci">auto make_data_pipe(PipeType d, C &&callable)</div><div class="ttdoc">function to construct a data pipe (tf::DataPipe)</div><div class="ttdef"><b>Definition</b> data_pipeline.hpp:171</div></div>
<div class="ttc" id="anamespacetf_html_abb7a11e41fd457f69e7ff45d4c769564a7b804a28d6154ab8007287532037f1d0"><div class="ttname"><a href="namespacetf.html#abb7a11e41fd457f69e7ff45d4c769564a7b804a28d6154ab8007287532037f1d0">tf::PipeType::SERIAL</a></div><div class="ttdeci">@ SERIAL</div><div class="ttdoc">serial type</div><div class="ttdef"><b>Definition</b> pipeline.hpp:117</div></div>
</div><!-- fragment --><p>The interface of <a class="el" href="classtf_1_1DataPipeline.html" title="class to create a data-parallel pipeline scheduling framework">tf::DataPipeline</a> is very similar to <a class="el" href="classtf_1_1Pipeline.html" title="class to create a pipeline scheduling framework">tf::Pipeline</a>, except that the library transparently manages the dataflow between pipes. To create a stage in a data-parallel pipeline, you should always use the helper function <a class="el" href="namespacetf.html#a8975fa5762088789adb0b60f38208309" title="function to construct a data pipe (tf::DataPipe)">tf::make_data_pipe</a>:</p>
<div class="fragment"><div class="line"><a class="code hl_function" href="namespacetf.html#a8975fa5762088789adb0b60f38208309">tf::make_data_pipe<int, std::string></a>(</div>
<div class="line"> <a class="code hl_enumvalue" href="namespacetf.html#abb7a11e41fd457f69e7ff45d4c769564a7b804a28d6154ab8007287532037f1d0">tf::PipeType::SERIAL</a>, </div>
<div class="line"> [](<span class="keywordtype">int</span>& input) { </div>
<div class="line"> <span class="keywordflow">return</span> std::to_string(input + 100);</div>
<div class="line"> }</div>
<div class="line">);</div>
</div><!-- fragment --><p>The helper function starts with a pair of an input and an output types in its template arguments. Both types will always be decayed to their original form using std::decay (e.g., <code>const int&</code> becomes <code>int</code>) for storage purpose. In terms of function arguments, the first argument specifies the direction of this data pipe, which can be either <a class="el" href="namespacetf.html#abb7a11e41fd457f69e7ff45d4c769564a7b804a28d6154ab8007287532037f1d0" title="serial type">tf::PipeType::SERIAL</a> or <a class="el" href="namespacetf.html#abb7a11e41fd457f69e7ff45d4c769564adf13a99b035d6f0bce4f44ab18eec8eb" title="parallel type">tf::PipeType::PARALLEL</a>, and the second argument is a callable to invoke by the pipeline scheduler. The callable must take the input data type in its first argument and returns a value of the output data type. Additionally, the callable can take a <a class="el" href="classtf_1_1Pipeflow.html" title="class to create a pipeflow object used by the pipe callable">tf::Pipeflow</a> reference in its second argument which allows you to query the runtime information of a stage task, such as its line number and token number.</p>
<div class="fragment"><div class="line"><a class="code hl_function" href="namespacetf.html#a8975fa5762088789adb0b60f38208309">tf::make_data_pipe<int, std::string></a>(</div>
<div class="line"> <a class="code hl_enumvalue" href="namespacetf.html#abb7a11e41fd457f69e7ff45d4c769564a7b804a28d6154ab8007287532037f1d0">tf::PipeType::SERIAL</a>, </div>
<div class="line"> [](<span class="keywordtype">int</span>& input, <a class="code hl_class" href="classtf_1_1Pipeflow.html">tf::Pipeflow</a>& pf) {</div>
<div class="line"> printf(<span class="stringliteral">"token=%lu, line=%lu\n"</span>, pf.<a class="code hl_function" href="classtf_1_1Pipeflow.html#a295e5d884665c076f4ef5d78139f7c51">token</a>(), pf.<a class="code hl_function" href="classtf_1_1Pipeflow.html#afee054e6a99965d4b3e36ff903227e6c">line</a>());</div>
<div class="line"> <span class="keywordflow">return</span> std::to_string(input + 100);</div>
<div class="line"> }</div>
<div class="line">)</div>
<div class="ttc" id="aclasstf_1_1Pipeflow_html_afee054e6a99965d4b3e36ff903227e6c"><div class="ttname"><a href="classtf_1_1Pipeflow.html#afee054e6a99965d4b3e36ff903227e6c">tf::Pipeflow::line</a></div><div class="ttdeci">size_t line() const</div><div class="ttdoc">queries the line identifier of the present token</div><div class="ttdef"><b>Definition</b> pipeline.hpp:64</div></div>
</div><!-- fragment --><dl class="section note"><dt>Note</dt><dd>By default, <a class="el" href="classtf_1_1DataPipeline.html" title="class to create a data-parallel pipeline scheduling framework">tf::DataPipeline</a> passes the data in reference to your callable at which you can take it in copy or in reference depending on application needs.</dd></dl>
<p>For the first pipe, the input type should always be <code>void</code> and the callable must take a <a class="el" href="classtf_1_1Pipeflow.html" title="class to create a pipeflow object used by the pipe callable">tf::Pipeflow</a> reference in its argument. In this example, we will stop the pipeline when processing five tokens.</p>
<div class="fragment"><div class="line"><a class="code hl_function" href="namespacetf.html#a8975fa5762088789adb0b60f38208309">tf::make_data_pipe<void, int></a>(<a class="code hl_enumvalue" href="namespacetf.html#abb7a11e41fd457f69e7ff45d4c769564a7b804a28d6154ab8007287532037f1d0">tf::PipeType::SERIAL</a>, [](<a class="code hl_class" href="classtf_1_1Pipeflow.html">tf::Pipeflow</a>& pf) -> <span class="keywordtype">int</span>{</div>
<div class="line"> <span class="keywordflow">if</span>(pf.<a class="code hl_function" href="classtf_1_1Pipeflow.html#a295e5d884665c076f4ef5d78139f7c51">token</a>() == 5) {</div>
<div class="line"> pf.<a class="code hl_function" href="classtf_1_1Pipeflow.html#a830b7f204cb87fff17e8d424918d9453">stop</a>();</div>
<div class="line"> <span class="keywordflow">return</span> 0; <span class="comment">// returns a dummy value</span></div>
<div class="line"> }</div>
<div class="line"> <span class="keywordflow">else</span> {</div>
<div class="line"> <span class="keywordflow">return</span> pf.<a class="code hl_function" href="classtf_1_1Pipeflow.html#a295e5d884665c076f4ef5d78139f7c51">token</a>();</div>
<div class="line"> }</div>
<div class="line">}),</div>
</div><!-- fragment --><p>Similarly, the output type of the last pipe should be <code>void</code> as no more data will go out of the final pipe.</p>
<div class="fragment"><div class="line"><a class="code hl_function" href="namespacetf.html#a8975fa5762088789adb0b60f38208309">tf::make_data_pipe<std::string, void></a>(<a class="code hl_enumvalue" href="namespacetf.html#abb7a11e41fd457f69e7ff45d4c769564a7b804a28d6154ab8007287532037f1d0">tf::PipeType::SERIAL</a>, [](std::string& input) {</div>
<div class="line"> std::cout << input << std::endl;</div>
<div class="line">})</div>
</div><!-- fragment --><p>Finally, you need to compose the pipeline graph by creating a module task (i.e., tf::Taskflow::compoased_of).</p>
<div class="fragment"><div class="line"><span class="comment">// build the pipeline graph using composition</span></div>
<div class="line">taskflow.composed_of(pl).name(<span class="stringliteral">"pipeline"</span>);</div>
<div class="line"> </div>
<div class="line"><span class="comment">// dump the pipeline graph structure (with composition)</span></div>
<div class="line">taskflow.dump(std::cout);</div>
<div class="line"> </div>
<div class="line"><span class="comment">// run the pipeline</span></div>
<div class="line">executor.<a class="code hl_function" href="classtf_1_1Executor.html#a519777f5783981d534e9e53b99712069">run</a>(taskflow).wait();</div>
</div><!-- fragment --><div class="dotgraph">
<iframe scrolling="no" frameborder="0" src="dot_pipeline_basic_dependency_graph.svg" width="566" height="252"><p><b>This browser is not able to show SVG: try Firefox, Chrome, Safari, or Opera instead.</b></p></iframe></div>
<h1><a class="anchor" id="UnderstandInternalDataStorage"></a>
Understand Internal Data Storage</h1>
<p>By default, <a class="el" href="classtf_1_1DataPipeline.html" title="class to create a data-parallel pipeline scheduling framework">tf::DataPipeline</a> uses <a href="https://en.cppreference.com/w/cpp/utility/variant">std::variant</a> to store a type-safe union of all input and output data types extracted from the given data pipes. To avoid false sharing, each line keeps a variant that is aligned with the cacheline size. When invoking a pipe callable, the input data is acquired in reference from the variant using <a href="https://en.cppreference.com/w/cpp/utility/variant/get">std::get</a>. When returning from a pipe callable, the output data is stored back to the variant using assignment operator. </p>
</div></div><!-- contents -->
</div><!-- PageDoc -->
</div><!-- doc-content -->
<!-- HTML footer for doxygen 1.13.1-->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
<ul>
<li class="navelem"><a class="el" href="Algorithms.html">Taskflow Algorithms</a></li>
<li class="footer">
Maintained by <a href="https://tsung-wei-huang.github.io/">Dr. Tsung-Wei Huang</a>
—
Generated by <a href="https://www.doxygen.org/index.html"><img class="footer" src="doxygen.svg" width="104" height="31" alt="doxygen"/></a> 1.13.1
</li>
</ul>
</div>