forked from taskflow/taskflow
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchapter6.html
More file actions
142 lines (140 loc) · 14 KB
/
chapter6.html
File metadata and controls
142 lines (140 loc) · 14 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.2.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('chapter6.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">C6: Manage Threads and Executor </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>We discuss in this chapter the thread management and task execution schemes in Cpp-Taskflow. We will go through the concept of <em>thread</em>, <em>ownership</em>, and <em>executor</em> in Cpp-Taskflow.</p>
<h1><a class="anchor" id="C6_MasterWorkersAndExecutor"></a>
Master, Workers, and Executor</h1>
<p>Cpp-Taskflow defines a strict relationship between the master and workers. Master is the thread that creates the executor object and workers are threads that invoke the callable target of a task. Each executor manages its own set of worker threads in a shared pool to schedule tasks. By default, Cpp-Taskflow uses <a class="elRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/thread/thread/hardware_concurrency.html">std::thread::hardware_concurrency</a> to decide the number of worker threads and <a class="elRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/thread/thread/get_id.html">std::thread::get_id</a> to identify the ownership between the master and workers.</p>
<div class="fragment"><div class="line"><a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/thread/thread/hardware_concurrency.html">std::thread::hardware_concurrency</a>() << std::endl; <span class="comment">// 8, for example</span></div><div class="line"><a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/thread/thread/get_id.html">std::thread::get_id</a>() << std::endl; <span class="comment">// master thread id</span></div><div class="line"><a class="code" href="classtf_1_1Executor.html">tf::Executor</a> exe1; <span class="comment">// create an executor with 8 workers</span></div><div class="line"><a class="code" href="classtf_1_1Executor.html">tf::Executor</a> exe2(4); <span class="comment">// create an executor with 4 workers</span></div></div><!-- fragment --><p>In the above example, the master thread owns both executor objects. The first executor <code>exe1</code> creates eight (default by <a class="elRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/thread/thread/hardware_concurrency.html">std::thread::hardware_concurrency</a>) worker threads and the second executor <code>exe2</code> creates four worker threads. Including the master thread, there will be a total of 1 + 8 + 4 = 13 threads running in this program. If you create an executor with zero workers, the master will carry out all the tasks by itself. That is, using one worker and zero worker are conceptually equivalent to each other since they both end up using one thread to run all tasks (see the snippet below).</p>
<div class="fragment"><div class="line"><a class="code" href="classtf_1_1Executor.html">tf::Executor</a> exe1(0); <span class="comment">// one master, zero worker (master to run tasks)</span></div><div class="line"><a class="code" href="classtf_1_1Executor.html">tf::Executor</a> exe2(1); <span class="comment">// one master, one worker (one thread to run tasks)</span></div></div><!-- fragment --><p>In general, the master thread is where you start the <code>main</code> function (main thread), while the worker threads are transparently maintained by its own executor. Cpp-Taskflow's executor implements a very efficient work-stealing algorithm to schedule the execution of tasks.</p>
<h1><a class="anchor" id="C6ThreadSafety"></a>
Thread Safety</h1>
<p><a class="el" href="classtf_1_1Executor.html" title="The executor class to run a taskflow graph. ">tf::Executor</a> is <em>NOT</em> thread-safe. Touching an executor from multiple threads can result in <em>undefined behavior</em>. Notice that this is different from running multiple taskflows on a same executor which is valid. Thread safety has nothing to do with the master nor the workers. It is completely safe to access an executor as long as only one thread presents at a time. However, we strongly recommend users to acknowledge the definition of the master and the workers, and separate the program control flow accordingly. Having a clear thread ownership can greatly reduce the chance of buggy implementations and undefined behaviors.</p>
<h1><a class="anchor" id="C6MonitorThreadActivities"></a>
Monitor Thread Activities</h1>
<p>Inspecting the thread activities is very important for performance analysis. It allows you to know when each task starts and ends participating in the task scheduling. Cpp-Taskflow provides a default observer class <a class="el" href="classtf_1_1ExecutorObserver.html" title="Default executor observer to dump the execution timelines. ">tf::ExecutorObserver</a> for this purpose. The following example shows how to create an observer from an executor.</p>
<div class="fragment"><div class="line"><a class="code" href="classtf_1_1Executor.html">tf::Executor</a> executor;</div><div class="line"><a class="code" href="classtf_1_1ExecutorObserver.html">tf::ExecutorObserver</a>* observer = executor.<a class="code" href="classtf_1_1Executor.html#a7f43cde72d3e0a17e2d006cbe7a41ff3">make_observer</a><<a class="code" href="classtf_1_1ExecutorObserver.html">tf::ExecutorObserver</a>>();</div></div><!-- fragment --><p>Note that each executor can only have an observer at a time. An observer will automatically record the start and end timestamps of each executed task. Users can query, dump or remove the timestamps through the <a class="el" href="classtf_1_1ExecutorObserver.html#a93d51307198abb9a1fc00a14904c3dd0" title="get the number of total tasks in the observer ">tf::ExecutorObserver::num_tasks</a>, <a class="el" href="classtf_1_1ExecutorObserver.html#a20f77a06e0f10dc67f7a5742add5b00a" title="dump the timelines in JSON format to an ostream ">tf::ExecutorObserver::dump</a> and <a class="el" href="classtf_1_1ExecutorObserver.html#adc78a004eaa25022a20fd16a35f607ce" title="clear the timeline data ">tf::ExecutorObserver::clear</a> methods.</p>
<div class="fragment"><div class="line"> 1. <a class="code" href="classtf_1_1Executor.html">tf::Executor</a> executor;</div><div class="line"> 2. <a class="code" href="classtf_1_1ExecutorObserver.html">tf::ExecutorObserver</a>* observer = executor.<a class="code" href="classtf_1_1Executor.html#a7f43cde72d3e0a17e2d006cbe7a41ff3">make_observer</a><<a class="code" href="classtf_1_1ExecutorObserver.html">tf::ExecutorObserver</a>>();</div><div class="line"> 3.</div><div class="line"> 4. executor.<a class="code" href="classtf_1_1Executor.html#a81f35d5b0a20ac0646447eb80d97c0aa">run</a>(taskflow).get(); <span class="comment">// do something</span></div><div class="line"> 5.</div><div class="line"> 6. <span class="comment">// Query the total number of tasks (number of timestamp pairs)</span></div><div class="line"> 7. <span class="keyword">auto</span> num_tasks = observer-><a class="code" href="classtf_1_1ExecutorObserver.html#a93d51307198abb9a1fc00a14904c3dd0">num_tasks</a>();</div><div class="line"> 8.</div><div class="line"> 9. <span class="comment">// Dump the timeline data in JSON format </span></div><div class="line">10. <a class="codeRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/string/basic_string.html">std::string</a> timelines_in_json = observer-><a class="code" href="classtf_1_1ExecutorObserver.html#a20f77a06e0f10dc67f7a5742add5b00a">dump</a>();</div><div class="line">11. </div><div class="line">12. <span class="comment">// Clear the timeline data</span></div><div class="line">13. observer-><a class="code" href="classtf_1_1ExecutorObserver.html#adc78a004eaa25022a20fd16a35f607ce">clear</a>();</div></div><!-- fragment --><p>Debrief:</p>
<ul>
<li>Line 2-4 creates an observer and a task dependency graph with four tasks and dispatch the tasks to execution. </li>
<li>Line 7 query the total number of tasks (number of timestamp pair) through observer </li>
<li>Line 10 dump the timestamps to a <a class="elRef" doxygen="/home/twhuang/PhD/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/string/basic_string.html">std::string</a> in JSON format </li>
<li>Line 13 remove all timestamps in the observer</li>
</ul>
<p>You can visualize the timeline data in a Chrome browser:</p>
<ul>
<li>Step 1: save the JSON timeline data to a file </li>
<li>Step 2: launch the Chrome browser and open a tab with the url: chrome://tracing </li>
<li>Step 3: load the JSON file</li>
</ul>
<div class="image">
<img src="timeline.png" alt="timeline.png" width="80%"/>
</div>
<p>Tasks will be categorized by the executing thread and each task is named with <em>i_j</em> where <em>i</em> is the thread id and <em>j</em> is the task number. You can pan or zoom in/out the timeline to get a detailed view.</p>
<h1><a class="anchor" id="C6CustomizeYourOwnObserver"></a>
Customize Your Own Observer</h1>
<p>You can derive your own observer from the base interface class <a class="el" href="classtf_1_1ExecutorObserverInterface.html" title="The interface class for creating an executor observer. ">tf::ExecutorObserverInterface</a> to customize the observing methods. </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>