-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Expand file tree
/
Copy pathExceptionHandling.html
More file actions
495 lines (493 loc) · 48.1 KB
/
Copy pathExceptionHandling.html
File metadata and controls
495 lines (493 loc) · 48.1 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
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
<!-- 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: Exception Handling</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>
<script type="text/javascript" src="darkmode_toggle.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('ExceptionHandling.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">Exception Handling</div></div>
</div><!--header-->
<div class="contents">
<div class="toc"><h3>Table of Contents</h3>
<ul>
<li class="level1">
<a href="#ExceptionHandlingWhyHard">Why Parallel Exception Handling is Hard</a>
</li>
<li class="level1">
<a href="#ExceptionHandlingLogic">How Taskflow Handles Exceptions</a>
<ul>
<li class="level2">
<a href="#Scenario1SynchronousExceptionPropagation">Scenario 1: Synchronous Propagation</a>
</li>
<li class="level2">
<a href="#Scenario2AsynchronousExceptionPropagation">Scenario 2: Asynchronous Propagation</a>
</li>
<li class="level2">
<a href="#Scenario3ContextualExceptionPropagation">Scenario 3: Contextual Propagation</a>
</li>
<li class="level2">
<a href="#ExceptionHandlingAlgorithmFlow">Algorithm Flow</a>
</li>
</ul>
</li>
<li class="level1">
<a href="#ExceptionHandlingRunningTaskflow">Catch an Exception from a Running Taskflow</a>
</li>
<li class="level1">
<a href="#ExceptionHandlingSubflow">Catch an Exception from a Subflow</a>
</li>
<li class="level1">
<a href="#ExceptionHandlingAsyncTask">Catch an Exception from an Async Task</a>
</li>
<li class="level1">
<a href="#ExceptionHandlingCorun">Catch an Exception from a Corun Loop</a>
</li>
<li class="level1">
<a href="#RetrieveTheExceptionPointerOfATask">Retrieve the Exception Pointer of a Task</a>
</li>
<li class="level1">
<a href="#DisableExceptionHandling">Disable Exception Handling at Compile Time</a>
</li>
</ul>
</div>
<div class="textblock"><p>Taskflow provides first-class support for exception handling in parallel programs — a capability that most task-parallel libraries deliberately omit. This page explains how exceptions propagate through task graphs, subflows, async tasks, and corun loops, and how to retrieve or suppress them.</p>
<h1><a class="anchor" id="ExceptionHandlingWhyHard"></a>
Why Parallel Exception Handling is Hard</h1>
<p>In a sequential program, exception handling is straightforward: an exception thrown in a function propagates up the call stack until it reaches a <code>catch</code> block or terminates the program.</p>
<div class="fragment"><div class="line"><span class="keywordflow">try</span> {</div>
<div class="line"> do_something();</div>
<div class="line">} <span class="keywordflow">catch</span>(std::exception e) {</div>
<div class="line"> std::cerr << e.what();</div>
<div class="line">}</div>
</div><!-- fragment --><p>However, in a parallel runtime, this mechanism breaks down entirely. Worker threads execute tasks independently of the application thread. When a task on worker thread 3 throws an exception, there is no call stack connection back to the <code>try</code> block the application wrote. The exception cannot simply propagate upward, as it will terminate the worker thread if left unhandled, corrupting the entire executor. A correct parallel runtime must therefore intercept every exception thrown inside a task, store it safely across thread boundaries, cancel the appropriate downstream tasks to avoid operating on invalid state, and re-raise the exception at the right point, either synchronously on a waiting thread or asynchronously via a future handle.</p>
<div class="dotgraph">
<iframe scrolling="no" frameborder="0" src="dot_exception_handling_hard.svg" width="863" height="419"><p><b>This browser is not able to show SVG: try Firefox, Chrome, Safari, or Opera instead.</b></p></iframe></div>
<p>Getting this right without sacrificing parallel efficiency is non-trivial, which is why most task-parallel libraries simply ignore the problem and leave exception safety entirely to the user. Taskflow handles it transparently.</p>
<h1><a class="anchor" id="ExceptionHandlingLogic"></a>
How Taskflow Handles Exceptions</h1>
<p>When a task throws an exception, Taskflow immediately cancels the execution of its parent taskflow — all subsequent tasks that depend on the throwing task are skipped. The exception itself is then routed to the appropriate reporting context according to the following three scenarios.</p>
<div class="dotgraph">
<iframe scrolling="no" frameborder="0" src="dot_exception-handling-logic.svg" width="874" height="258"><p><b>This browser is not able to show SVG: try Firefox, Chrome, Safari, or Opera instead.</b></p></iframe></div>
<p>When multiple scenarios apply, Taskflow prioritises them in order: Scenario 1 first, then Scenario 2, then Scenario 3.</p>
<h2><a class="anchor" id="Scenario1SynchronousExceptionPropagation"></a>
Scenario 1: Synchronous Propagation</h2>
<p>If the taskflow is executed in a blocking context — such as <a class="el" href="classtf_1_1Executor.html#a8fcd9e0557922bb8194999f0cd433ea8" title="runs a target graph and waits until it completes using an internal worker of this executor">tf::Executor::corun</a> or <a class="el" href="classtf_1_1Subflow.html#a59fcac1323e70d920088dd37bd0be245" title="enables the subflow to join its parent task">tf::Subflow::join</a> — the exception is immediately rethrown to the calling thread as soon as it is detected. The executor does not defer or aggregate it.</p>
<div class="fragment"><div class="line"><span class="keywordflow">try</span> {</div>
<div class="line"> executor.corun(taskflow);</div>
<div class="line">}</div>
<div class="line"><span class="keywordflow">catch</span> (<span class="keyword">const</span> std::exception& e) {</div>
<div class="line"> std::cerr << e.what();</div>
<div class="line">}</div>
</div><!-- fragment --><h2><a class="anchor" id="Scenario2AsynchronousExceptionPropagation"></a>
Scenario 2: Asynchronous Propagation</h2>
<p>When tasks are launched via <a class="el" href="classtf_1_1Executor.html#a519777f5783981d534e9e53b99712069" title="runs a taskflow once">tf::Executor::run</a> or <a class="el" href="classtf_1_1Executor.html#af960048056f7c6b5bc71f4f526f05df7" title="creates a parameterized asynchronous task to run the given function">tf::Executor::async</a>, the exception is captured and stored in the shared state of the returned <a class="el" href="classtf_1_1Future.html" title="class to access the result of an execution">tf::Future</a> or <code>std::future</code>. It is rethrown when the application calls <code>get()</code> on that future.</p>
<div class="fragment"><div class="line"><a class="code hl_class" href="classtf_1_1Future.html">tf::Future<void></a> fu = executor.run(taskflow);</div>
<div class="line"><span class="keywordflow">try</span> {</div>
<div class="line"> fu.get();</div>
<div class="line">}</div>
<div class="line"><span class="keywordflow">catch</span> (<span class="keyword">const</span> std::exception& e) {</div>
<div class="line"> std::cerr << e.what();</div>
<div class="line">}</div>
<div class="ttc" id="aclasstf_1_1Future_html"><div class="ttname"><a href="classtf_1_1Future.html">tf::Future</a></div><div class="ttdoc">class to access the result of an execution</div><div class="ttdef"><b>Definition</b> taskflow.hpp:640</div></div>
</div><!-- fragment --><h2><a class="anchor" id="Scenario3ContextualExceptionPropagation"></a>
Scenario 3: Contextual Propagation</h2>
<p>This scenario is reached only when no blocking context and no observable shared state exist — for example, a task launched via <a class="el" href="classtf_1_1Executor.html#a0461cb2c459c9f9473c72af06af9c701" title="similar to tf::Executor::async but does not return a future object">tf::Executor::silent_async</a>. In this case Taskflow first attempts to propagate the exception to the nearest parent execution context. If no such parent exists, the exception is silently suppressed and stored locally within the throwing task.</p>
<div class="fragment"><div class="line"><span class="comment">// No parent context: exception is silently suppressed</span></div>
<div class="line">executor.silent_async([&]() {</div>
<div class="line"> <span class="keywordflow">throw</span> std::runtime_error(<span class="stringliteral">"this exception is suppressed"</span>);</div>
<div class="line">});</div>
<div class="line"> </div>
<div class="line"><span class="comment">// Parent context exists: exception propagates to the task group</span></div>
<div class="line">executor.silent_async([&]() {</div>
<div class="line"> <a class="code hl_class" href="classtf_1_1TaskGroup.html">tf::TaskGroup</a> tg = executor.task_group();</div>
<div class="line"> tg.<a class="code hl_function" href="classtf_1_1TaskGroup.html#acf90acfcaf9468adc56bf647208a9e78">silent_async</a>([]() {</div>
<div class="line"> <span class="keywordflow">throw</span> std::runtime_error(<span class="stringliteral">"this propagates to the parent task group"</span>);</div>
<div class="line"> });</div>
<div class="line"> <span class="keywordflow">try</span> {</div>
<div class="line"> tg.<a class="code hl_function" href="classtf_1_1TaskGroup.html#a1f481dc466e3107a08346d1a124677bc">corun</a>();</div>
<div class="line"> }</div>
<div class="line"> <span class="keywordflow">catch</span> (<span class="keyword">const</span> std::runtime_error& e) {</div>
<div class="line"> std::cerr << e.what();</div>
<div class="line"> }</div>
<div class="line">});</div>
<div class="ttc" id="aclasstf_1_1TaskGroup_html"><div class="ttname"><a href="classtf_1_1TaskGroup.html">tf::TaskGroup</a></div><div class="ttdoc">class to create a task group from a task</div><div class="ttdef"><b>Definition</b> task_group.hpp:61</div></div>
<div class="ttc" id="aclasstf_1_1TaskGroup_html_a1f481dc466e3107a08346d1a124677bc"><div class="ttname"><a href="classtf_1_1TaskGroup.html#a1f481dc466e3107a08346d1a124677bc">tf::TaskGroup::corun</a></div><div class="ttdeci">void corun()</div><div class="ttdoc">corun all tasks spawned by this task group with other workers</div><div class="ttdef"><b>Definition</b> task_group.hpp:721</div></div>
<div class="ttc" id="aclasstf_1_1TaskGroup_html_acf90acfcaf9468adc56bf647208a9e78"><div class="ttname"><a href="classtf_1_1TaskGroup.html#acf90acfcaf9468adc56bf647208a9e78">tf::TaskGroup::silent_async</a></div><div class="ttdeci">void silent_async(F &&f)</div><div class="ttdoc">runs the given function asynchronously without returning any future object</div><div class="ttdef"><b>Definition</b> task_group.hpp:752</div></div>
</div><!-- fragment --><h2><a class="anchor" id="ExceptionHandlingAlgorithmFlow"></a>
Algorithm Flow</h2>
<p>The figure below illustrates the full decision process. When a task throws, the runtime walks up the task hierarchy to mark the execution path as exceptional and identifies two kinds of anchor nodes: an <em>explicit</em> <em>anchor</em> (a blocking context such as <code>corun</code> or <code>join</code>) and an <em>implicit</em> <em>anchor</em> (a parent task group). If an explicit anchor is found, the exception is captured and rethrown on the waiting application thread (Scenario 1). If no explicit anchor exists but a shared state is associated, the exception is stored for asynchronous retrieval (Scenario 2). Otherwise the runtime propagates to the nearest implicit anchor if one exists, or suppresses the exception locally (Scenario 3). This algorithm ensures exceptions are reported whenever a reporting context is available while preserving safe and efficient parallel execution.</p>
<div class="dotgraph">
<iframe scrolling="no" frameborder="0" src="dot_exception-handling-algorithm.svg" width="838" height="707"><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="ExceptionHandlingRunningTaskflow"></a>
Catch an Exception from a Running Taskflow</h1>
<p>The most common case is catching an exception thrown by a task inside a taskflow submitted with <a class="el" href="classtf_1_1Executor.html#a519777f5783981d534e9e53b99712069" title="runs a taskflow once">tf::Executor::run</a>. The executor captures the exception and stores it in the shared state of the returned <a class="el" href="classtf_1_1Future.html" title="class to access the result of an execution">tf::Future</a>. Calling <code>get()</code> rethrows it:</p>
<div class="fragment"><div class="line"><a class="code hl_class" href="classtf_1_1Executor.html">tf::Executor</a> executor;</div>
<div class="line"><a class="code hl_class" href="classtf_1_1Taskflow.html">tf::Taskflow</a> taskflow;</div>
<div class="line"> </div>
<div class="line">taskflow.<a class="code hl_function" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([]() { <span class="keywordflow">throw</span> std::runtime_error(<span class="stringliteral">"exception"</span>); });</div>
<div class="line"> </div>
<div class="line"><span class="keywordflow">try</span> {</div>
<div class="line"> executor.<a class="code hl_function" href="classtf_1_1Executor.html#a519777f5783981d534e9e53b99712069">run</a>(taskflow).get();</div>
<div class="line">}</div>
<div class="line"><span class="keywordflow">catch</span> (<span class="keyword">const</span> std::runtime_error& e) {</div>
<div class="line"> std::cerr << e.what() << <span class="charliteral">'\n'</span>;</div>
<div class="line">}</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_1FlowBuilder_html_a4d52a7fe2814b264846a2085e931652c"><div class="ttname"><a href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">tf::FlowBuilder::emplace</a></div><div class="ttdeci">Task emplace(C &&callable)</div><div class="ttdoc">creates a static task</div><div class="ttdef"><b>Definition</b> flow_builder.hpp:1781</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><!-- fragment --><dl class="section note"><dt>Note</dt><dd><a class="el" href="classtf_1_1Future.html" title="class to access the result of an execution">tf::Future</a> is derived from <a href="https://en.cppreference.com/w/cpp/thread/future">std::future</a> and inherits all standard exception-handling behaviours defined by the C++ standard.</dd></dl>
<p>When a task throws, the executor immediately cancels the rest of the taskflow — all tasks that depend on the throwing task are skipped. The following example shows this with a two-task chain where <code>B</code> depends on <code>A:</code> </p>
<div class="fragment"><div class="line"><a class="code hl_class" href="classtf_1_1Executor.html">tf::Executor</a> executor;</div>
<div class="line"><a class="code hl_class" href="classtf_1_1Taskflow.html">tf::Taskflow</a> taskflow;</div>
<div class="line"> </div>
<div class="line"><a class="code hl_class" href="classtf_1_1Task.html">tf::Task</a> A = taskflow.<a class="code hl_function" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([]() {</div>
<div class="line"> <span class="keywordflow">throw</span> std::runtime_error(<span class="stringliteral">"exception on A"</span>);</div>
<div class="line">});</div>
<div class="line"><a class="code hl_class" href="classtf_1_1Task.html">tf::Task</a> B = taskflow.<a class="code hl_function" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([]() {</div>
<div class="line"> std::cout << <span class="stringliteral">"Task B\n"</span>; <span class="comment">// never printed</span></div>
<div class="line">});</div>
<div class="line">A.<a class="code hl_function" href="classtf_1_1Task.html#a8c78c453295a553c1c016e4062da8588">precede</a>(B);</div>
<div class="line"> </div>
<div class="line"><span class="keywordflow">try</span> {</div>
<div class="line"> executor.<a class="code hl_function" href="classtf_1_1Executor.html#a519777f5783981d534e9e53b99712069">run</a>(taskflow).get();</div>
<div class="line">}</div>
<div class="line"><span class="keywordflow">catch</span> (<span class="keyword">const</span> std::runtime_error& e) {</div>
<div class="line"> std::cerr << e.what() << <span class="charliteral">'\n'</span>;</div>
<div class="line">}</div>
<div class="ttc" id="aclasstf_1_1Task_html"><div class="ttname"><a href="classtf_1_1Task.html">tf::Task</a></div><div class="ttdoc">class to create a task handle over a taskflow node</div><div class="ttdef"><b>Definition</b> task.hpp:569</div></div>
<div class="ttc" id="aclasstf_1_1Task_html_a8c78c453295a553c1c016e4062da8588"><div class="ttname"><a href="classtf_1_1Task.html#a8c78c453295a553c1c016e4062da8588">tf::Task::precede</a></div><div class="ttdeci">Task & precede(Ts &&... tasks)</div><div class="ttdoc">adds precedence links from this to other tasks</div><div class="ttdef"><b>Definition</b> task.hpp:1305</div></div>
</div><!-- fragment --><div class="fragment"><div class="line">exception on A</div>
</div><!-- fragment --><p>When multiple tasks throw exceptions concurrently, Taskflow propagates exactly one to the <code>catch</code> block. The others are silently caught and stored within their respective tasks (see <a class="el" href="#RetrieveTheExceptionPointerOfATask">Retrieve the Exception Pointer of a Task</a>). In the diamond taskflow below, both <code>B</code> and <code>C</code> may throw simultaneously — only one exception reaches the application:</p>
<div class="fragment"><div class="line"><a class="code hl_class" href="classtf_1_1Executor.html">tf::Executor</a> executor;</div>
<div class="line"><a class="code hl_class" href="classtf_1_1Taskflow.html">tf::Taskflow</a> taskflow;</div>
<div class="line"> </div>
<div class="line"><span class="keyword">auto</span> [A, B, C, D] = taskflow.<a class="code hl_function" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>(</div>
<div class="line"> []() { std::cout << <span class="stringliteral">"Task A\n"</span>; },</div>
<div class="line"> []() {</div>
<div class="line"> std::cout << <span class="stringliteral">"Task B\n"</span>;</div>
<div class="line"> <span class="keywordflow">throw</span> std::runtime_error(<span class="stringliteral">"Exception on Task B"</span>);</div>
<div class="line"> },</div>
<div class="line"> []() {</div>
<div class="line"> std::cout << <span class="stringliteral">"Task C\n"</span>;</div>
<div class="line"> <span class="keywordflow">throw</span> std::runtime_error(<span class="stringliteral">"Exception on Task C"</span>);</div>
<div class="line"> },</div>
<div class="line"> []() { std::cout << <span class="stringliteral">"Task D\n"</span>; } <span class="comment">// skipped</span></div>
<div class="line">);</div>
<div class="line"> </div>
<div class="line">A.<a class="code hl_function" href="classtf_1_1Task.html#a8c78c453295a553c1c016e4062da8588">precede</a>(B, C);</div>
<div class="line">D.<a class="code hl_function" href="classtf_1_1Task.html#a331b1b726555072e7c7d10941257f664">succeed</a>(B, C);</div>
<div class="line"> </div>
<div class="line"><span class="keywordflow">try</span> {</div>
<div class="line"> executor.<a class="code hl_function" href="classtf_1_1Executor.html#a519777f5783981d534e9e53b99712069">run</a>(taskflow).get();</div>
<div class="line">}</div>
<div class="line"><span class="keywordflow">catch</span> (<span class="keyword">const</span> std::runtime_error& e) {</div>
<div class="line"> std::cerr << e.what() << <span class="charliteral">'\n'</span>; <span class="comment">// either B's or C's exception</span></div>
<div class="line">}</div>
<div class="ttc" id="aclasstf_1_1Task_html_a331b1b726555072e7c7d10941257f664"><div class="ttname"><a href="classtf_1_1Task.html#a331b1b726555072e7c7d10941257f664">tf::Task::succeed</a></div><div class="ttdeci">Task & succeed(Ts &&... tasks)</div><div class="ttdoc">adds precedence links from other tasks to this</div><div class="ttdef"><b>Definition</b> task.hpp:1313</div></div>
</div><!-- fragment --><h1><a class="anchor" id="ExceptionHandlingSubflow"></a>
Catch an Exception from a Subflow</h1>
<p>When you explicitly join a subflow with <a class="el" href="classtf_1_1Subflow.html#a59fcac1323e70d920088dd37bd0be245" title="enables the subflow to join its parent task">tf::Subflow::join</a>, you can catch exceptions thrown by its child tasks at the join point:</p>
<div class="fragment"><div class="line"><a class="code hl_class" href="classtf_1_1Executor.html">tf::Executor</a> executor;</div>
<div class="line"><a class="code hl_class" href="classtf_1_1Taskflow.html">tf::Taskflow</a> taskflow;</div>
<div class="line"> </div>
<div class="line">taskflow.<a class="code hl_function" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([](<a class="code hl_class" href="classtf_1_1Subflow.html">tf::Subflow</a>& sf) {</div>
<div class="line"> <a class="code hl_class" href="classtf_1_1Task.html">tf::Task</a> A = sf.<a class="code hl_function" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([]() {</div>
<div class="line"> std::cout << <span class="stringliteral">"Task A\n"</span>;</div>
<div class="line"> <span class="keywordflow">throw</span> std::runtime_error(<span class="stringliteral">"exception on A"</span>);</div>
<div class="line"> });</div>
<div class="line"> <a class="code hl_class" href="classtf_1_1Task.html">tf::Task</a> B = sf.<a class="code hl_function" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([]() {</div>
<div class="line"> std::cout << <span class="stringliteral">"Task B\n"</span>; <span class="comment">// skipped</span></div>
<div class="line"> });</div>
<div class="line"> A.<a class="code hl_function" href="classtf_1_1Task.html#a8c78c453295a553c1c016e4062da8588">precede</a>(B);</div>
<div class="line"> </div>
<div class="line"> <span class="keywordflow">try</span> {</div>
<div class="line"> sf.<a class="code hl_function" href="classtf_1_1Subflow.html#a59fcac1323e70d920088dd37bd0be245">join</a>();</div>
<div class="line"> }</div>
<div class="line"> <span class="keywordflow">catch</span> (<span class="keyword">const</span> std::runtime_error& e) {</div>
<div class="line"> std::cerr << <span class="stringliteral">"caught at join: "</span> << e.what() << <span class="charliteral">'\n'</span>;</div>
<div class="line"> }</div>
<div class="line">});</div>
<div class="line"> </div>
<div class="line">executor.<a class="code hl_function" href="classtf_1_1Executor.html#a519777f5783981d534e9e53b99712069">run</a>(taskflow).get();</div>
<div class="ttc" id="aclasstf_1_1Subflow_html"><div class="ttname"><a href="classtf_1_1Subflow.html">tf::Subflow</a></div><div class="ttdoc">class to construct a subflow graph from the execution of a dynamic task</div><div class="ttdef"><b>Definition</b> flow_builder.hpp:1956</div></div>
<div class="ttc" id="aclasstf_1_1Subflow_html_a59fcac1323e70d920088dd37bd0be245"><div class="ttname"><a href="classtf_1_1Subflow.html#a59fcac1323e70d920088dd37bd0be245">tf::Subflow::join</a></div><div class="ttdeci">void join()</div><div class="ttdoc">enables the subflow to join its parent task</div></div>
</div><!-- fragment --><div class="fragment"><div class="line">Task A</div>
<div class="line">caught at join: exception on A</div>
</div><!-- fragment --><p>If you do not catch the exception at the join point, it propagates up to the parent taskflow and is rethrown when the application calls <code>get()</code>:</p>
<div class="fragment"><div class="line"><a class="code hl_class" href="classtf_1_1Executor.html">tf::Executor</a> executor;</div>
<div class="line"><a class="code hl_class" href="classtf_1_1Taskflow.html">tf::Taskflow</a> taskflow;</div>
<div class="line"> </div>
<div class="line">taskflow.<a class="code hl_function" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([](<a class="code hl_class" href="classtf_1_1Subflow.html">tf::Subflow</a>& sf) {</div>
<div class="line"> <a class="code hl_class" href="classtf_1_1Task.html">tf::Task</a> A = sf.<a class="code hl_function" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([]() {</div>
<div class="line"> std::cout << <span class="stringliteral">"Task A\n"</span>;</div>
<div class="line"> <span class="keywordflow">throw</span> std::runtime_error(<span class="stringliteral">"exception on A"</span>);</div>
<div class="line"> });</div>
<div class="line"> <a class="code hl_class" href="classtf_1_1Task.html">tf::Task</a> B = sf.<a class="code hl_function" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([]() { std::cout << <span class="stringliteral">"Task B\n"</span>; });</div>
<div class="line"> A.<a class="code hl_function" href="classtf_1_1Task.html#a8c78c453295a553c1c016e4062da8588">precede</a>(B);</div>
<div class="line"> sf.<a class="code hl_function" href="classtf_1_1Subflow.html#a59fcac1323e70d920088dd37bd0be245">join</a>(); <span class="comment">// exception propagates upward</span></div>
<div class="line">});</div>
<div class="line"> </div>
<div class="line"><span class="keywordflow">try</span> {</div>
<div class="line"> executor.<a class="code hl_function" href="classtf_1_1Executor.html#a519777f5783981d534e9e53b99712069">run</a>(taskflow).get();</div>
<div class="line">}</div>
<div class="line"><span class="keywordflow">catch</span> (<span class="keyword">const</span> std::runtime_error& e) {</div>
<div class="line"> std::cerr << <span class="stringliteral">"caught at taskflow: "</span> << e.what() << <span class="charliteral">'\n'</span>;</div>
<div class="line">}</div>
</div><!-- fragment --><div class="fragment"><div class="line">Task A</div>
<div class="line">caught at taskflow: exception on A</div>
</div><!-- fragment --><h1><a class="anchor" id="ExceptionHandlingAsyncTask"></a>
Catch an Exception from an Async Task</h1>
<p><a class="el" href="classtf_1_1Executor.html#af960048056f7c6b5bc71f4f526f05df7" title="creates a parameterized asynchronous task to run the given function">tf::Executor::async</a> behaves like <code>std::async:</code> the exception is stored in the returned <code>std::future</code> and rethrown on <code>get()</code>:</p>
<div class="fragment"><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">auto</span> fu = executor.<a class="code hl_function" href="classtf_1_1Executor.html#af960048056f7c6b5bc71f4f526f05df7">async</a>([]() {</div>
<div class="line"> <span class="keywordflow">throw</span> std::runtime_error(<span class="stringliteral">"exception"</span>);</div>
<div class="line">});</div>
<div class="line"> </div>
<div class="line"><span class="keywordflow">try</span> {</div>
<div class="line"> fu.get();</div>
<div class="line">}</div>
<div class="line"><span class="keywordflow">catch</span> (<span class="keyword">const</span> std::runtime_error& e) {</div>
<div class="line"> std::cerr << e.what() << <span class="charliteral">'\n'</span>;</div>
<div class="line">}</div>
<div class="ttc" id="aclasstf_1_1Executor_html_af960048056f7c6b5bc71f4f526f05df7"><div class="ttname"><a href="classtf_1_1Executor.html#af960048056f7c6b5bc71f4f526f05df7">tf::Executor::async</a></div><div class="ttdeci">auto async(P &&params, F &&func)</div><div class="ttdoc">creates a parameterized asynchronous task to run the given function</div></div>
</div><!-- fragment --><p><a class="el" href="classtf_1_1Executor.html#a0461cb2c459c9f9473c72af06af9c701" title="similar to tf::Executor::async but does not return a future object">tf::Executor::silent_async</a> returns no future, so an exception thrown inside it is handled contextually (Scenario 3): propagated to the nearest parent context if one exists, or silently suppressed otherwise:</p>
<div class="fragment"><div class="line"><a class="code hl_class" href="classtf_1_1Taskflow.html">tf::Taskflow</a> taskflow;</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="comment">// no parent context — exception is silently suppressed</span></div>
<div class="line">executor.<a class="code hl_function" href="classtf_1_1Executor.html#a0461cb2c459c9f9473c72af06af9c701">silent_async</a>([]() {</div>
<div class="line"> <span class="keywordflow">throw</span> std::runtime_error(<span class="stringliteral">"suppressed"</span>);</div>
<div class="line">});</div>
<div class="line"> </div>
<div class="line"><span class="comment">// inside a Runtime task — exception propagates to the parent taskflow</span></div>
<div class="line">taskflow.<a class="code hl_function" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([&](<a class="code hl_class" href="classtf_1_1Runtime.html">tf::Runtime</a>& rt) {</div>
<div class="line"> rt.<a class="code hl_function" href="classtf_1_1Runtime.html#a0ce29efa2106c8c5a1432e4a55ab2e05">silent_async</a>([]() {</div>
<div class="line"> <span class="keywordflow">throw</span> std::runtime_error(<span class="stringliteral">"propagated to taskflow"</span>);</div>
<div class="line"> });</div>
<div class="line">});</div>
<div class="line"> </div>
<div class="line"><span class="keywordflow">try</span> {</div>
<div class="line"> executor.<a class="code hl_function" href="classtf_1_1Executor.html#a519777f5783981d534e9e53b99712069">run</a>(taskflow).get();</div>
<div class="line">}</div>
<div class="line"><span class="keywordflow">catch</span> (<span class="keyword">const</span> std::runtime_error& e) {</div>
<div class="line"> std::cerr << e.what() << <span class="charliteral">'\n'</span>;</div>
<div class="line">}</div>
<div class="ttc" id="aclasstf_1_1Executor_html_a0461cb2c459c9f9473c72af06af9c701"><div class="ttname"><a href="classtf_1_1Executor.html#a0461cb2c459c9f9473c72af06af9c701">tf::Executor::silent_async</a></div><div class="ttdeci">void silent_async(P &&params, F &&func)</div><div class="ttdoc">similar to tf::Executor::async but does not return a future object</div></div>
<div class="ttc" id="aclasstf_1_1Runtime_html"><div class="ttname"><a href="classtf_1_1Runtime.html">tf::Runtime</a></div><div class="ttdoc">class to create a runtime task</div><div class="ttdef"><b>Definition</b> runtime.hpp:47</div></div>
<div class="ttc" id="aclasstf_1_1Runtime_html_a0ce29efa2106c8c5a1432e4a55ab2e05"><div class="ttname"><a href="classtf_1_1Runtime.html#a0ce29efa2106c8c5a1432e4a55ab2e05">tf::Runtime::silent_async</a></div><div class="ttdeci">void silent_async(F &&f)</div><div class="ttdoc">runs the given function asynchronously without returning any future object</div><div class="ttdef"><b>Definition</b> runtime.hpp:667</div></div>
</div><!-- fragment --><h1><a class="anchor" id="ExceptionHandlingCorun"></a>
Catch an Exception from a Corun Loop</h1>
<p><a class="el" href="classtf_1_1Executor.html#a8fcd9e0557922bb8194999f0cd433ea8" title="runs a target graph and waits until it completes using an internal worker of this executor">tf::Executor::corun</a> and <a class="el" href="classtf_1_1Runtime.html#aba54a7cacffb54f5eb133730d256a7c4" title="corun all tasks spawned by this runtime with other workers">tf::Runtime::corun</a> run a graph to completion on the calling thread, so any exception thrown inside is immediately rethrown (Scenario 1). You can catch it directly at the <code>corun</code> call site:</p>
<div class="fragment"><div class="line"><a class="code hl_class" href="classtf_1_1Executor.html">tf::Executor</a> executor;</div>
<div class="line"><a class="code hl_class" href="classtf_1_1Taskflow.html">tf::Taskflow</a> taskflow1, taskflow2;</div>
<div class="line"> </div>
<div class="line">taskflow1.<a class="code hl_function" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([]() {</div>
<div class="line"> <span class="keywordflow">throw</span> std::runtime_error(<span class="stringliteral">"exception"</span>);</div>
<div class="line">});</div>
<div class="line">taskflow2.<a class="code hl_function" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([&]() {</div>
<div class="line"> <span class="keywordflow">try</span> {</div>
<div class="line"> executor.<a class="code hl_function" href="classtf_1_1Executor.html#a8fcd9e0557922bb8194999f0cd433ea8">corun</a>(taskflow1);</div>
<div class="line"> }</div>
<div class="line"> <span class="keywordflow">catch</span> (<span class="keyword">const</span> std::runtime_error& e) {</div>
<div class="line"> std::cerr << <span class="stringliteral">"caught at corun: "</span> << e.what() << <span class="charliteral">'\n'</span>;</div>
<div class="line"> }</div>
<div class="line">});</div>
<div class="line"> </div>
<div class="line">executor.<a class="code hl_function" href="classtf_1_1Executor.html#a519777f5783981d534e9e53b99712069">run</a>(taskflow2).get();</div>
<div class="ttc" id="aclasstf_1_1Executor_html_a8fcd9e0557922bb8194999f0cd433ea8"><div class="ttname"><a href="classtf_1_1Executor.html#a8fcd9e0557922bb8194999f0cd433ea8">tf::Executor::corun</a></div><div class="ttdeci">void corun(T &target)</div><div class="ttdoc">runs a target graph and waits until it completes using an internal worker of this executor</div></div>
</div><!-- fragment --><p>The same applies to <a class="el" href="classtf_1_1Runtime.html#aba54a7cacffb54f5eb133730d256a7c4" title="corun all tasks spawned by this runtime with other workers">tf::Runtime::corun</a>:</p>
<div class="fragment"><div class="line"><a class="code hl_class" href="classtf_1_1Executor.html">tf::Executor</a> executor;</div>
<div class="line"><a class="code hl_class" href="classtf_1_1Taskflow.html">tf::Taskflow</a> taskflow1, taskflow2;</div>
<div class="line"> </div>
<div class="line">taskflow1.<a class="code hl_function" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([]() {</div>
<div class="line"> <span class="keywordflow">throw</span> std::runtime_error(<span class="stringliteral">"exception"</span>);</div>
<div class="line">});</div>
<div class="line">taskflow2.<a class="code hl_function" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([&](<a class="code hl_class" href="classtf_1_1Runtime.html">tf::Runtime</a>& rt) {</div>
<div class="line"> <span class="keywordflow">try</span> {</div>
<div class="line"> rt.<a class="code hl_function" href="classtf_1_1Runtime.html#aba54a7cacffb54f5eb133730d256a7c4">corun</a>(taskflow1);</div>
<div class="line"> }</div>
<div class="line"> <span class="keywordflow">catch</span> (<span class="keyword">const</span> std::runtime_error& e) {</div>
<div class="line"> std::cerr << <span class="stringliteral">"caught at corun: "</span> << e.what() << <span class="charliteral">'\n'</span>;</div>
<div class="line"> }</div>
<div class="line">});</div>
<div class="line"> </div>
<div class="line">executor.<a class="code hl_function" href="classtf_1_1Executor.html#a519777f5783981d534e9e53b99712069">run</a>(taskflow2).get();</div>
<div class="ttc" id="aclasstf_1_1Runtime_html_aba54a7cacffb54f5eb133730d256a7c4"><div class="ttname"><a href="classtf_1_1Runtime.html#aba54a7cacffb54f5eb133730d256a7c4">tf::Runtime::corun</a></div><div class="ttdeci">void corun()</div><div class="ttdoc">corun all tasks spawned by this runtime with other workers</div><div class="ttdef"><b>Definition</b> runtime.hpp:642</div></div>
</div><!-- fragment --><p>If the exception is not caught at the <code>corun</code> call site, it propagates to the parent task and then to the parent taskflow:</p>
<div class="fragment"><div class="line"><a class="code hl_class" href="classtf_1_1Executor.html">tf::Executor</a> executor;</div>
<div class="line"><a class="code hl_class" href="classtf_1_1Taskflow.html">tf::Taskflow</a> taskflow1, taskflow2;</div>
<div class="line"> </div>
<div class="line">taskflow1.<a class="code hl_function" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([]() {</div>
<div class="line"> <span class="keywordflow">throw</span> std::runtime_error(<span class="stringliteral">"exception"</span>);</div>
<div class="line">});</div>
<div class="line">taskflow2.<a class="code hl_function" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>([&](<a class="code hl_class" href="classtf_1_1Runtime.html">tf::Runtime</a>& rt) {</div>
<div class="line"> rt.<a class="code hl_function" href="classtf_1_1Runtime.html#aba54a7cacffb54f5eb133730d256a7c4">corun</a>(taskflow1); <span class="comment">// not caught here</span></div>
<div class="line">});</div>
<div class="line"> </div>
<div class="line"><span class="keywordflow">try</span> {</div>
<div class="line"> executor.<a class="code hl_function" href="classtf_1_1Executor.html#a519777f5783981d534e9e53b99712069">run</a>(taskflow2).get();</div>
<div class="line">}</div>
<div class="line"><span class="keywordflow">catch</span> (<span class="keyword">const</span> std::runtime_error& e) {</div>
<div class="line"> std::cerr << <span class="stringliteral">"caught at taskflow: "</span> << e.what() << <span class="charliteral">'\n'</span>;</div>
<div class="line">}</div>
</div><!-- fragment --><h1><a class="anchor" id="RetrieveTheExceptionPointerOfATask"></a>
Retrieve the Exception Pointer of a Task</h1>
<p>When multiple tasks throw simultaneously, Taskflow propagates exactly one exception to the application. The remaining exceptions are stored inside their respective tasks and can be inspected via <a class="el" href="classtf_1_1Task.html#a2f893050f81e40b12df4209bce4fa66b" title="retrieves the exception pointer of this task">tf::Task::exception_ptr</a>, which returns a non-null <code>std::exception_ptr</code> if the task threw, or <code>nullptr</code> if it completed normally.</p>
<p>This is useful for post-mortem analysis: after catching the propagated exception, you can walk the task graph and check which other tasks also threw:</p>
<div class="fragment"><div class="line"><a class="code hl_class" href="classtf_1_1Executor.html">tf::Executor</a> executor(2);</div>
<div class="line"><a class="code hl_class" href="classtf_1_1Taskflow.html">tf::Taskflow</a> taskflow;</div>
<div class="line">std::atomic<size_t> arrivals{0};</div>
<div class="line"> </div>
<div class="line"><span class="comment">// Both B and C throw; the barrier ensures they execute truly concurrently</span></div>
<div class="line"><span class="comment">// so neither is cancelled before it gets a chance to throw.</span></div>
<div class="line"><span class="keyword">auto</span> [B, C] = taskflow.<a class="code hl_function" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c">emplace</a>(</div>
<div class="line"> [&]() {</div>
<div class="line"> ++arrivals; <span class="keywordflow">while</span> (arrivals != 2);</div>
<div class="line"> <span class="keywordflow">throw</span> std::runtime_error(<span class="stringliteral">"exception from B"</span>);</div>
<div class="line"> },</div>
<div class="line"> [&]() {</div>
<div class="line"> ++arrivals; <span class="keywordflow">while</span> (arrivals != 2);</div>
<div class="line"> <span class="keywordflow">throw</span> std::runtime_error(<span class="stringliteral">"exception from C"</span>);</div>
<div class="line"> }</div>
<div class="line">);</div>
<div class="line"> </div>
<div class="line"><span class="keywordflow">try</span> {</div>
<div class="line"> executor.<a class="code hl_function" href="classtf_1_1Executor.html#a519777f5783981d534e9e53b99712069">run</a>(taskflow).get();</div>
<div class="line">}</div>
<div class="line"><span class="keywordflow">catch</span> (<span class="keyword">const</span> std::runtime_error& e) {</div>
<div class="line"> std::cerr << <span class="stringliteral">"propagated: "</span> << e.what() << <span class="charliteral">'\n'</span>;</div>
<div class="line">}</div>
<div class="line"> </div>
<div class="line"><span class="comment">// Exactly one task holds a stored exception; the other was propagated</span></div>
<div class="line">assert((B.<a class="code hl_function" href="classtf_1_1Task.html#a2f893050f81e40b12df4209bce4fa66b">exception_ptr</a>() != <span class="keyword">nullptr</span>) != (C.exception_ptr() != <span class="keyword">nullptr</span>));</div>
<div class="line"> </div>
<div class="line"><span class="comment">// Inspect the stored exception</span></div>
<div class="line"><span class="keywordflow">if</span> (<span class="keyword">auto</span> ep = B.<a class="code hl_function" href="classtf_1_1Task.html#a2f893050f81e40b12df4209bce4fa66b">exception_ptr</a>()) {</div>
<div class="line"> <span class="keywordflow">try</span> { std::rethrow_exception(ep); }</div>
<div class="line"> <span class="keywordflow">catch</span> (<span class="keyword">const</span> std::runtime_error& e) {</div>
<div class="line"> std::cerr << <span class="stringliteral">"stored in B: "</span> << e.what() << <span class="charliteral">'\n'</span>;</div>
<div class="line"> }</div>
<div class="line">}</div>
<div class="line"><span class="keywordflow">if</span> (<span class="keyword">auto</span> ep = C.exception_ptr()) {</div>
<div class="line"> <span class="keywordflow">try</span> { std::rethrow_exception(ep); }</div>
<div class="line"> <span class="keywordflow">catch</span> (<span class="keyword">const</span> std::runtime_error& e) {</div>
<div class="line"> std::cerr << <span class="stringliteral">"stored in C: "</span> << e.what() << <span class="charliteral">'\n'</span>;</div>
<div class="line"> }</div>
<div class="line">}</div>
<div class="ttc" id="aclasstf_1_1Task_html_a2f893050f81e40b12df4209bce4fa66b"><div class="ttname"><a href="classtf_1_1Task.html#a2f893050f81e40b12df4209bce4fa66b">tf::Task::exception_ptr</a></div><div class="ttdeci">std::exception_ptr exception_ptr() const</div><div class="ttdoc">retrieves the exception pointer of this task</div><div class="ttdef"><b>Definition</b> task.hpp:1470</div></div>
</div><!-- fragment --><h1><a class="anchor" id="DisableExceptionHandling"></a>
Disable Exception Handling at Compile Time</h1>
<p>In performance-critical applications without exception safety requirements, you can disable Taskflow's exception handling entirely at compile time by defining <code>TF_DISABLE_EXCEPTION_HANDLING:</code> </p>
<div class="fragment"><div class="line">g++ -DTF_DISABLE_EXCEPTION_HANDLING your_program.cpp</div>
</div><!-- fragment --><p>This removes all <code>try-<code>catch</code> blocks</code> from the Taskflow runtime, producing a leaner binary and potentially faster execution.</p>
<dl class="section attention"><dt>Attention</dt><dd>With exception handling disabled, any exception thrown inside a task is unchecked and will propagate uncontrolled through the runtime, likely terminating the program or causing undefined behaviour. Use this option only if your application guarantees that no task will throw. </dd></dl>
</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="Cookbook.html">Cookbook</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>