You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
C.precede(D); // D runs after C // +---->| C |-----+
52
+
A.precede(B); // A runs before B // | A | | D |
53
+
A.precede(C); // A runs before C // +---+ +-^-+
54
+
B.precede(D); // B runs before D // | +---+ |
55
+
C.precede(D); // C runs before D // +---->| C |-----+
56
56
// +---+
57
-
tf.wait_for_all(); // block until finished
57
+
tf.wait_for_all(); // block until finish
58
58
59
59
return 0;
60
60
}
@@ -732,7 +732,7 @@ The folder `example/` contains several examples and is a great place to learn to
732
732
|[reduce.cpp](./example/reduce.cpp)| performs reduce operations over linear containers |
733
733
|[subflow.cpp](./example/subflow.cpp)| demonstrates how to create a subflow graph that spawns three dynamic tasks |
734
734
|[threadpool.cpp](./example/threadpool.cpp)| benchmarks different threadpool implementations |
735
-
|[taskflow.cpp](./example/taskflow.cpp)| benchmarks different threadpool implementations|
735
+
|[taskflow.cpp](./example/taskflow.cpp)| benchmarks taskflow on different task dependency graphs|
736
736
|[threadpool_cxx14.cpp](./example/threadpool_cxx14.cpp)| shows use of the C++14-compatible threadpool implementation, which may be used when you have no inter-task (taskflow) dependencies to express |
737
737
738
738
# Get Involved
@@ -769,16 +769,13 @@ that incorporate complex task dependencies.
769
769
770
770
Please [let me know][email me] if I forgot your project!
771
771
772
-
If you work for a company using Cpp-Taskflow or has the means to do so,
773
-
please consider [financial support][PayMe].
774
-
775
772
# License
776
773
777
774
Cpp-Taskflow is licensed under the [MIT License](./LICENSE).
Copy file name to clipboardExpand all lines: doc/cookbook/dispatch.md
+43-36Lines changed: 43 additions & 36 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,7 +1,7 @@
1
1
# Execute a Task Dependency Graph
2
2
3
3
After you create a task dependency graph,
4
-
you need to dispatch it for execution.
4
+
you need to dispatch it to threads for execution
5
5
In this tutorial, we will show you how to execute a
6
6
task dependency graph.
7
7
@@ -14,20 +14,27 @@ task dependency graph.
14
14
15
15
# Graph and Topology
16
16
17
-
Each taskflow object has exactly one graph at a time to represent
18
-
task dependencies constructed so far.
17
+
Each taskflow object has exactly one graph at a time that represents
18
+
the tasks and the dependencies constructed so far.
19
19
The graph exists until users dispatch it for execution.
20
-
We call a dispatched graph a *topology*.
20
+
In Cpp-Taskflow, we call a dispatched graph a *topology*.
21
+
A topology is a data structure that wraps up a dispatched graph
22
+
and stores a few metadata obtained at runtime.
21
23
Each taskflow object has a list of topologies to keep track of the
22
24
execution status of dispatched graphs.
23
-
All tasks are executed in a shared thread pool.
25
+
Users can retrieve this information later on for graph inspection and debugging.
26
+
27
+
All tasks are executed in a shared thread storage coupled with a
28
+
*task scheduler* to decide which thread runs which task.
29
+
Cpp-Taskflow provides two ways to dispatch a task dependency graph,
30
+
*blocking* and *non-blocking*.
24
31
25
32
# Blocking Execution
26
33
27
34
One way to dispatch the present task dependency graph
28
35
is to use the method `wait_for_all`.
29
-
Calling `wait_for_all`will dispatch the present graph to a shared thread storage
30
-
and block the program until all tasks finish.
36
+
Calling `wait_for_all`dispatches the graph to threads and blocks the program flow
37
+
until all tasks finish.
31
38
32
39
```cpp
33
40
1: tf::Taskflow tf(4);
@@ -47,16 +54,16 @@ All topologies will be cleaned up as well.
47
54
48
55
Another way to dispatch the present task dependency graph
49
56
is to use the method `dispatch` or `silent_dispatch`.
50
-
These two methods will dispatch the present graph to threads
51
-
and returns immediately without blocking the program.
52
-
Non-blocking methods allows the program to perform other computations
53
-
that can overlap with the execution of topologies.
57
+
These two methods both dispatch the present graph to threads
58
+
and return immediately without blocking the program flow.
59
+
Non-blocking methods allow the program to perform other computations
60
+
that can overlap the graph execution.
54
61
55
62
```cpp
56
63
1: tf::Taskflow tf(4);
57
64
2:
58
-
3: auto A = tf.silent_emplace([] () { std::cout << "TaskA\n"; });
59
-
4: auto B = tf.silent_emplace([] () { std::cout << "TaskB\n"; });
65
+
3: auto A = tf.silent_emplace([] () { std::cout << "Task A\n"; });
66
+
4: auto B = tf.silent_emplace([] () { std::cout << "Task B\n"; });
60
67
5: A.precede(B);
61
68
6:
62
69
7: auto F = tf.dispatch();
@@ -68,16 +75,15 @@ that can overlap with the execution of topologies.
68
75
Debrief:
69
76
70
77
+ Line 1-5 creates a graph with two tasks and one dependency
71
-
+ Line 7 dispatches this graph to a topology
72
-
and obtains a `std::future` to access its execution status
73
-
+ Line 8-9 performs some computations to overlap the execution of this topology
78
+
+ Line 7 dispatches this graph
79
+
and obtains a `std::future`object to access its execution status
80
+
+ Line 8-9 performs some computations to overlap the execution of task A and task B
74
81
+ Line 10 blocks the program until this topology finishes
75
82
76
83
If you do not care the status of a dispatched graph,
77
84
use the method `silent_dispatch`.
78
85
This method does not return anything.
79
86
80
-
81
87
```cpp
82
88
1: tf::Taskflow tf(4);
83
89
2:
@@ -92,11 +98,12 @@ This method does not return anything.
92
98
93
99
# Wait on Topologies
94
100
95
-
When you call `dispatch` or `silent_dispatch`,
96
-
the taskflow object will dispatch the present graph to threads
97
-
and maintain a list of data structures called *topology*
98
-
to store the execution status.
99
-
These topologies are not cleaned up automatically on completion.
101
+
Unlike `wait_for_all`, calling `dispatch` or `silent_dispatch`
102
+
will not clean up the topologies upon completion.
103
+
This allows users to dump the graph structure, in particular, created from dynamic tasking.
104
+
However, it may be necessary at some points of the program
105
+
to synchronize with the previously dispatched graphs.
106
+
Cpp-Taskflow provides a method `wait_for_topologies` for this purpose.
100
107
101
108
102
109
```cpp
@@ -120,20 +127,21 @@ These topologies are not cleaned up automatically on completion.
120
127
Debrief
121
128
+ Line 1 creates a taskflow object with four worker threads
122
129
+ Line 3-5 creates a dependency graph of two tasks and one dependency
123
-
+ Line 7 dispatches the present graph to threads and obtains a future object
130
+
+ Line 7 dispatches this graph to threads and obtains a future object for users
124
131
to access the execution status
125
132
+ Line 9 starts with a new dependency graph with one task
126
-
+ Line 11 dispatches the present graph to threads
127
-
+ Line 13 blocks the program until all running topologies finish
133
+
+ Line 11 dispatches the graph to threads
134
+
+ Line 13 blocks the program until both graphs finish
128
135
129
-
It's clear now Line 9 overlaps the execution of the first graph.
130
-
After Line 11, there are two topologies running inside the taskflow object.
136
+
It is clear now Line 9 overlaps the execution of the first graph.
137
+
After Line 11, there are two topologies in the taskflow object.
131
138
Calling the method `wait_for_topologies` blocks the
132
-
program until both complete.
139
+
program until both graph complete.
133
140
134
141
# Example 1: Multiple Dispatches
135
142
136
-
The example below demonstrates how to create multiple task dependency graphs and dispatch each of them asynchronously.
143
+
The example below demonstrates how to create multiple task dependency graphs and
144
+
dispatch each of them asynchronously.
137
145
138
146
```cpp
139
147
1: #include <taskflow/taskflow.hpp>
@@ -171,14 +179,13 @@ Debrief:
171
179
+ Line 12-19 defines a function that iteratively creates a task dependency graph and dispatches it asynchronously
172
180
+ Line 23 starts the procedure of multiple dispatches
173
181
174
-
Notice in Line 24 the counter ends up with 20.
175
-
The destructor of a taskflow object will not leave until all running
176
-
topologies finish.
182
+
Notice in Line 24 the counter ends up being 20.
183
+
By default, destructing a taskflow object will wait on all topologies to finish.
177
184
178
185
# Example 2: Connect Two Dependency Graphs
179
186
180
-
The example demonstrates how to use the `std::future` to manually impose a dependency link
181
-
on two dispatched graphs.
187
+
The example demonstrates how to use the `std::future` to explicitly impose a dependency
188
+
link on two dispatched graphs.
182
189
183
190
```cpp
184
191
1: #include <taskflow/taskflow.hpp>
@@ -233,10 +240,10 @@ on two dispatched graphs.
233
240
Debrief:
234
241
+ Line 5 creates a taskflow object with four worker threads
235
242
+ Line 7-8 creates a vector of integer items and an integer variable to store the summation value
236
-
+ Line 10-21 creates a dependency graph that resizes the vector size and fills it with sequentially increasing values starting with zero
243
+
+ Line 10-21 creates a dependency graph that resizes the vector and fills it with sequentially increasing values starting with zero
237
244
+ Line 23-39 creates another dependency graph that sums up the values in the vector
238
245
+ Line 25-27 creates a task that initializes the variable `sum` to zero, and overlaps its execution with the first dependency graph
239
-
+ Line 30-35 creates a task that blocks until the first dependency graph completes and then sums up all integer values in the propertly initialized vector
246
+
+ 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
240
247
+ Line 42 blocks until the second dependency graph finishes
241
248
+ Line 44 puts an assertion guard on the final summation value
0 commit comments