Skip to content

Commit 6806f47

Browse files
updated lifetime in cookbook
1 parent 4a7c39c commit 6806f47

File tree

7 files changed

+115
-13
lines changed

7 files changed

+115
-13
lines changed

doc/cookbook/a.out

-77 KB
Binary file not shown.

doc/cookbook/dispatch.md

Lines changed: 103 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ you need to dispatch it to threads for execution
55
In this tutorial, we will show you how to execute a
66
task dependency graph.
77

8-
+ [Graph and Topology](#Graph-and-Topology)
9-
+ [Blocking Execution](#Blocking-Execution)
10-
+ [Non-blocking Execution](#Non-blocking-Execution)
11-
+ [Wait on Topologies](#Wait-on-Topologies)
12-
+ [Example 1: Multiple Dispatches](#Example-1-Multiple-Dispatches)
13-
+ [Example 2: Connect Two Dependency Graphs](#Example-2-Connect-Two-Dependency-Graphs)
8+
+ [Graph and Topology](#graph-and-topology)
9+
+ [Blocking Execution](#blocking-execution)
10+
+ [Non-blocking Execution](#non-blocking-execution)
11+
+ [Wait on Topologies](#wait-on-topologies)
12+
+ [Lifetime of a Graph](#lifetime-of-a-graph)
13+
+ [Example 1: Multiple Dispatches](#example-1-multiple-dispatches)
14+
+ [Example 2: Connect Two Dependency Graphs](#example-2-connect-two-dependency-graphs)
1415

1516
# Graph and Topology
1617

@@ -138,6 +139,98 @@ After Line 11, there are two topologies in the taskflow object.
138139
Calling the method `wait_for_topologies` blocks the
139140
program until both graph complete.
140141

142+
# Lifetime of a Graph
143+
144+
In Cpp-Taskflow, the lifetime of a task sticks with its parent graph.
145+
The lifetime of a task mostly refers to the user-given callable objects,
146+
including those captured by a lambda expression.
147+
When a graph is destroyed, all of its tasks are destroyed.
148+
Consider the following example that uses
149+
[std::shared_ptr][std::shared_ptr] to demonstrate the lifetime of a graph and
150+
the impact on its task.
151+
152+
```cpp
153+
1: tf::Taskflow tf;
154+
2:
155+
3: auto ptr = std::make_shared<int>(0);
156+
4:
157+
5: std::cout << "reference count before A and B: " << ptr.use_count() << '\n';
158+
6:
159+
7: auto A = tf.silent_emplace([ptr] () {
160+
8: std::cout << "reference count at A: " << ptr.use_count() << '\n';
161+
9: });
162+
10:
163+
11: auto B = tf.silent_emplace([ptr] () {
164+
12: std::cout << "reference count at B: " << ptr.use_count() << '\n';
165+
13: });
166+
14:
167+
15: A.precede(B);
168+
16:
169+
17: std::cout << "reference count after A and B: " << ptr.use_count() << '\n';
170+
18:
171+
19: tf.wait_for_all();
172+
20:
173+
21: std::cout << "reference count after A and B: " << ptr.use_count() << '\n';
174+
```
175+
176+
The output is as follows:
177+
178+
```bash
179+
reference count before A and B: 1
180+
reference count after A and B: 3
181+
reference count at A: 3
182+
reference count at B: 3
183+
reference count after A and B: 1
184+
```
185+
186+
In Line 5, we created a shared pointer object with one reference count on itself.
187+
After Line 7-13, the reference count increases by two because
188+
task A and task B both capture a copy of the shared pointer.
189+
The lifetime of a task has nothing to do with its dependency constraints,
190+
as shown in Line 8, Line 12, and Line 17.
191+
However, Line 19 dispatches the graph to threads and cleans up its data structure
192+
upon finish, including all associated tasks.
193+
Therefore, the reference count in Line 21 drops down to one (owner at Line 3).
194+
195+
Now let's use the same example but dispatch the graph asynchronously.
196+
197+
```cpp
198+
1: tf::Taskflow tf;
199+
2:
200+
3: auto ptr = std::make_shared<int>(0);
201+
4:
202+
5: std::cout << "reference count before A and B: " << ptr.use_count() << '\n';
203+
6:
204+
7: auto A = tf.silent_emplace([ptr] () {
205+
8: std::cout << "reference count at A: " << ptr.use_count() << '\n';
206+
9: });
207+
10:
208+
11: auto B = tf.silent_emplace([ptr] () {
209+
12: std::cout << "reference count at B: " << ptr.use_count() << '\n';
210+
13: });
211+
14:
212+
15: A.precede(B);
213+
16:
214+
17: std::cout << "reference count after A and B: " << ptr.use_count() << '\n';
215+
18:
216+
19: tf.dispatch().get(); // dispatch the graph without destroying it
217+
20:
218+
21: std::cout << "reference count after A and B: " << ptr.use_count() << '\n';
219+
```
220+
221+
In Line 19, we replace `wait_for_all` with `disaptch` to dispatch the graph asynchronously
222+
without cleaning up its data structures upon completion.
223+
In other words, task A and task B remains un-destructed after Line 19,
224+
and the reference count at this point remains three.
225+
226+
```bash
227+
reference count before A and B: 1
228+
reference count after A and B: 3
229+
reference count at A: 3
230+
reference count at B: 3
231+
reference count after A and B: 3
232+
```
233+
141234
# Example 1: Multiple Dispatches
142235

143236
The example below demonstrates how to create multiple task dependency graphs and
@@ -253,3 +346,7 @@ The result of the variable `sum` ends up being the summation over
253346
the integer sequence `[0, 1, 2, ..., 1024)`.
254347

255348

349+
* * *
350+
351+
[std::shared_ptr]: https://en.cppreference.com/w/cpp/memory/shared_ptr
352+

doc/cookbook/hello_world.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Hello World
1+
# Write Your First Cpp-Taskflow Program
22

33
In this tutorial, we are going to demonstrate how to write a Cpp-Taskflow's
44
"hello world" program.

doc/cookbook/task.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ The lifetime of a task mostly refers to the user-given callable object,
118118
including captured values.
119119
As long as the graph is alive,
120120
all the associated tasks remain their existence.
121+
We recommend the users to read [Lifetime of a Graph][Lifetime of a Graph].
121122
122123
123124
---
@@ -257,4 +258,5 @@ Only the latest information will be used.
257258
[std::function]: https://en.cppreference.com/w/cpp/utility/functional/function
258259
[std::invoke]: https://en.cppreference.com/w/cpp/utility/functional/invoke
259260
[std::future]: https://en.cppreference.com/w/cpp/thread/future
261+
[Lifetime of a Graph]: dispatch.md#lifetime-of-a-graph
260262

doc/faq.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
This page summarizes a list of frequently asked questions about Cpp-Taskflow.
44
If you cannot find a solution here, please post an issue [here][Github issues].
55

6-
+ [General Questions](#General-Questions)
7-
+ [Compilation Issues](#Compilation-Issues)
8-
+ [Programming Questions](#Programming-Questions)
6+
+ [General Questions](#general-questions)
7+
+ [Compilation Issues](#compilation-issues)
8+
+ [Programming Questions](#programming-questions)
99

1010
---
1111

@@ -109,6 +109,11 @@ that wraps up a particular node in a graph
109109
and provides a set of methods for you to assign different attributes to the task
110110
such as adding dependencies, naming, and assigning a new work.
111111
112+
## Q: What is the Lifetime of a Task and a Graph?
113+
114+
The lifetime of a task sticks with its parent graph. A task is not destroyed until its parent
115+
graph is destroyed.
116+
112117
## Q: Is taskflow thread-safe?
113118
114119
No, the taskflow object is not thread-safe. You can't create tasks from multiple threads

doc/home.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ software architecture, C++ API, and library usages.
1212

1313
# Cookbook
1414

15-
+ [Write your First Cpp-Taskflow Program](cookbook/hello_world.md)
15+
+ [Write Your First Cpp-Taskflow Program](cookbook/hello_world.md)
1616
+ [Understand the Task](cookbook/task.md)
1717
+ [Execute a Task Dependency Graph](cookbook/dispatch.md)
1818
+ [Create a Parallel For-loop Graph](cookbook/parallel_for.md)

example/simple.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77

88
int main(){
99

10-
tf::Taskflow tf(std::thread::hardware_concurrency());
11-
1210
auto [A, B, C, D] = tf.silent_emplace( // the taskflow graph
1311
[] () { std::cout << "TaskA\n"; }, //
1412
[] () { std::cout << "TaskB\n"; }, // +---+

0 commit comments

Comments
 (0)