1 #pragma once
2
3 #include "task.hpp"
4
5 namespace tf {
6
7 /**
8 @class FlowBuilder
9
10 @brief building methods of a task dependency graph
11
12 */
13 class FlowBuilder {
14
15 friend class Executor;
16
17 public:
18
19 /**
20 @brief creates a static task from a given callable object
21
22 @tparam C callable type
23
24 @param callable a callable object constructible from std::function<void()>
25
26 @return a Task handle
27 */
28 template <typename C>
29 std::enable_if_t<is_static_task_v<C>, Task> emplace(C&& callable);
30
31 /**
32 @brief creates a dynamic task from a given callable object
33
34 @tparam C callable type
35
36 @param callable a callable object constructible from std::function<void(Subflow&)>
37
38 @return a Task handle
39 */
40 template <typename C>
41 std::enable_if_t<is_dynamic_task_v<C>, Task> emplace(C&& callable);
42
43 /**
44 @brief creates a condition task from a given callable object
45
46 @tparam C callable type
47
48 @param callable a callable object constructible from std::function<int()>
49
50 @return a Task handle
51 */
52 template <typename C>
53 std::enable_if_t<is_condition_task_v<C>, Task> emplace(C&& callable);
54
55 #ifdef TF_ENABLE_CUDA
56 /**
57 @brief creates a cudaflow task from a given callable object
58
59 @tparam C callable type
60
61 @param callable a callable object constructible from std::function<void(cudaFlow&)>
62
63 @return a Task handle
64 */
65 template <typename C>
66 std::enable_if_t<is_cudaflow_task_v<C>, Task> emplace(C&& callable);
67 #endif
68
69 /**
70 @brief creates multiple tasks from a list of callable objects
71
72 @tparam C... callable types
73
74 @param callables one or multiple callable objects constructible from each task category
75
76 @return a Task handle
77 */
78 template <typename... C, std::enable_if_t<(sizeof...(C)>1), void>* = nullptr>
79 auto emplace(C&&... callables);
80
81 /**
82 @brief creates a module task from a taskflow
83
84 @param taskflow a taskflow object for the module
85 @return a Task handle
86 */
87 Task composed_of(Taskflow& taskflow);
88
89 /**
90 @brief creates an empty task
91
92 @return a Task handle
93 */
94 Task placeholder();
95
96 /**
97 @brief adds adjacent dependency links to a linear list of tasks
98
99 @param tasks a vector of tasks
100 */
101 void linearize(std::vector<Task>& tasks);
102
103 /**
104 @brief adds adjacent dependency links to a linear list of tasks
105
106 @param tasks an initializer list of tasks
107 */
108 void linearize(std::initializer_list<Task> tasks);
109
110 // ------------------------------------------------------------------------
111 // parallel iterations
112 // ------------------------------------------------------------------------
113
114 /**
115 @brief constructs a STL-styled parallel-for task
116
117 @tparam B beginning iterator type
118 @tparam E ending iterator type
119 @tparam C callable type
120
121 @param first iterator to the beginning (inclusive)
122 @param last iterator to the end (exclusive)
123 @param callable a callable object to apply to the dereferenced iterator
124
125 @return a Task handle
126
127 The task spawns a subflow that applies the callable object to each object obtained by dereferencing every iterator in the range <tt>[first, last)</tt>. By default, we employ the guided partition algorithm with chunk size equal to one.
128
129 This method is equivalent to the parallel execution of the following loop:
130
131 @code{.cpp}
132 for(auto itr=first; itr!=last; itr++) {
133 callable(*itr);
134 }
135 @endcode
136
137 Arguments templated to enable stateful passing using std::reference_wrapper.
138
139 The callable needs to take a single argument of the dereferenced type.
140 */
141 template <typename B, typename E, typename C>
142 Task for_each(B&& first, E&& last, C&& callable);
143
144 /**
145 @brief constructs a STL-styled parallel-for task using the guided partition algorithm
146
147 @tparam B beginning iterator type
148 @tparam E ending iterator type
149 @tparam C callable type
150 @tparam H chunk size type
151
152 @param beg iterator to the beginning (inclusive)
153 @param end iterator to the end (exclusive)
154 @param callable a callable object to apply to the dereferenced iterator
155 @param chunk_size chunk size
156
157 @return a Task handle
158
159 The task spawns a subflow that applies the callable object to each object obtained by dereferencing every iterator in the range <tt>[beg, end)</tt>. The runtime partitions the range into chunks of the given chunk size, where each chunk is processed by a worker.
160
161 Arguments are templated to enable stateful passing using std::reference_wrapper.
162
163 The callable needs to take a single argument of the dereferenced type.
164 */
165 template <typename B, typename E, typename C, typename H = size_t>
166 Task for_each_guided(B&& beg, E&& end, C&& callable, H&& chunk_size = 1);
167
168 /**
169 @brief constructs a STL-styled parallel-for task using the dynamic partition algorithm
170
171 @tparam B beginning iterator type
172 @tparam E ending iterator type
173 @tparam C callable type
174 @tparam H chunk size type
175
176 @param beg iterator to the beginning (inclusive)
177 @param end iterator to the end (exclusive)
178 @param callable a callable object to apply to the dereferenced iterator
179 @param chunk_size chunk size
180
181 @return a Task handle
182
183 The task spawns a subflow that applies the callable object to each object obtained by dereferencing every iterator in the range <tt>[beg, end)</tt>. The runtime partitions the range into chunks of the given chunk size, where each chunk is processed by a worker.
184
185 Arguments are templated to enable stateful passing using std::reference_wrapper.
186
187 The callable needs to take a single argument of the dereferenced type.
188 */
189 template <typename B, typename E, typename C, typename H = size_t>
190 Task for_each_dynamic(B&& beg, E&& end, C&& callable, H&& chunk_size = 1);
191
192 /**
193 @brief constructs a STL-styled parallel-for task using the dynamic partition algorithm
194
195 @tparam B beginning iterator type
196 @tparam E ending iterator type
197 @tparam C callable type
198 @tparam H chunk size type
199
200 @param beg iterator to the beginning (inclusive)
201 @param end iterator to the end (exclusive)
202 @param callable a callable object to apply to the dereferenced iterator
203 @param chunk_size chunk size
204
205 @return a Task handle
206
207 The task spawns a subflow that applies the callable object to each object obtained by dereferencing every iterator in the range <tt>[beg, end)</tt>. The runtime partitions the range into chunks of the given chunk size, where each chunk is processed by a worker. When the given chunk size is zero, the runtime distributes the work evenly across workers.
208
209 Arguments are templated to enable stateful passing using std::reference_wrapper.
210
211 The callable needs to take a single argument of the dereferenced type.
212 */
213 template <typename B, typename E, typename C, typename H = size_t>
214 Task for_each_static(
215 B&& beg, E&& end, C&& callable, H&& chunk_size = 0
216 );
217
218 /**
219 @brief constructs an index-based parallel-for task
220
221 @tparam B beginning index type (must be integral)
222 @tparam E ending index type (must be integral)
223 @tparam S step type (must be integral)
224 @tparam C callable type
225
226 @param first index of the beginning (inclusive)
227 @param last index of the end (exclusive)
228 @param step step size
229 @param callable a callable object to apply to each valid index
230
231 @return a Task handle
232
233 The task spawns a subflow that applies the callable object to each index in the range <tt>[first, last)</tt> with the step size. By default, we employ the guided partition algorithm with chunk size equal to one.
234
235 This method is equivalent to the parallel execution of the following loop:
236
237 @code{.cpp}
238 // case 1: step size is positive
239 for(auto i=first; i<last; i+=step) {
240 callable(i);
241 }
242
243 // case 2: step size is negative
244 for(auto i=first, i>last; i+=step) {
245 callable(i);
246 }
247 @endcode
248
249 Arguments are templated to enable stateful passing using std::reference_wrapper.
250
251 The callable needs to take a single argument of the index type.
252
253 */
254 template <typename B, typename E, typename S, typename C>
255 Task for_each_index(B&& first, E&& last, S&& step, C&& callable);
256
257 /**
258 @brief constructs an index-based parallel-for task using the guided partition algorithm.
259
260 @tparam B beginning index type (must be integral)
261 @tparam E ending index type (must be integral)
262 @tparam S step type (must be integral)
263 @tparam C callable type
264 @tparam H chunk size type
265
266 @param beg index of the beginning (inclusive)
267 @param end index of the end (exclusive)
268 @param step step size
269 @param callable a callable object to apply to each valid index
270 @param chunk_size chunk size (default 1)
271
272 @return a Task handle
273
274 The task spawns a subflow that applies the callable object to each index in the range <tt>[beg, end)</tt> with the step size. The runtime partitions the range into chunks of the given size, where each chunk is processed by a worker.
275
276 Arguments are templated to enable stateful passing using std::reference_wrapper.
277
278 The callable needs to take a single argument of the index type.
279 */
280 template <typename B, typename E, typename S, typename C, typename H = size_t>
281 Task for_each_index_guided(
282 B&& beg, E&& end, S&& step, C&& callable, H&& chunk_size = 1
283 );
284
285 /**
286 @brief constructs an index-based parallel-for task using the dynamic partition algorithm.
287
288 @tparam B beginning index type (must be integral)
289 @tparam E ending index type (must be integral)
290 @tparam S step type (must be integral)
291 @tparam C callable type
292 @tparam H chunk size type
293
294 @param beg index of the beginning (inclusive)
295 @param end index of the end (exclusive)
296 @param step step size
297 @param callable a callable object to apply to each valid index
298 @param chunk_size chunk size (default 1)
299
300 @return a Task handle
301
302 The task spawns a subflow that applies the callable object to each index in the range <tt>[beg, end)</tt> with the step size. The runtime partitions the range into chunks of the given size, where each chunk is processed by a worker.
303
304 Arguments are templated to enable stateful passing using std::reference_wrapper.
305
306 The callable needs to take a single argument of the index type.
307 */
308 template <typename B, typename E, typename S, typename C, typename H = size_t>
309 Task for_each_index_dynamic(
310 B&& beg, E&& end, S&& step, C&& callable, H&& chunk_size = 1
311 );
312
313 /**
314 @brief constructs an index-based parallel-for task using the static partition algorithm.
315
316 @tparam B beginning index type (must be integral)
317 @tparam E ending index type (must be integral)
318 @tparam S step type (must be integral)
319 @tparam C callable type
320 @tparam H chunk size type
321
322 @param beg index of the beginning (inclusive)
323 @param end index of the end (exclusive)
324 @param step step size
325 @param callable a callable object to apply to each valid index
326 @param chunk_size chunk size (default 0)
327
328 @return a Task handle
329
330 The task spawns a subflow that applies the callable object to each index in the range <tt>[beg, end)</tt> with the step size. The runtime partitions the range into chunks of the given size, where each chunk is processed by a worker. When the given chunk size is zero, the runtime distributes the work evenly across workers.
331
332 Arguments are templated to enable stateful passing using std::reference_wrapper.
333
334 The callable needs to take a single argument of the index type.
335 */
336 template <typename B, typename E, typename S, typename C, typename H = size_t>
337 Task for_each_index_static(
338 B&& beg, E&& end, S&& step, C&& callable, H&& chunk_size = 0
339 );
340
341 // ------------------------------------------------------------------------
342 // reduction
343 // ------------------------------------------------------------------------
344
345 /**
346 @brief constructs a STL-styled parallel-reduce task
347
348 @tparam B beginning iterator type
349 @tparam E ending iterator type
350 @tparam T result type
351 @tparam O binary reducer type
352
353 @param first iterator to the beginning (inclusive)
354 @param last iterator to the end (exclusive)
355 @param init initial value of the reduction and the storage for the reduced result
356 @param bop binary operator that will be applied
357
358 @return a Task handle
359
360 The task spawns a subflow to perform parallel reduction over @c init and the elements in the range <tt>[first, last)</tt>. The reduced result is store in @c init. The runtime partitions the range into chunks of the given chunk size, where each chunk is processed by a worker. By default, we employ the guided partition algorithm.
361
362 This method is equivalent to the parallel execution of the following loop:
363
364 @code{.cpp}
365 for(auto itr=first; itr!=last; itr++) {
366 init = bop(init, *itr);
367 }
368 @endcode
369
370 Arguments are templated to enable stateful passing using std::reference_wrapper.
371 */
372 template <typename B, typename E, typename T, typename O>
373 Task reduce(B&& first, E&& last, T& init, O&& bop);
374
375 /**
376 @brief constructs a STL-styled parallel-reduce task using the guided partition algorithm
377
378 @tparam B beginning iterator type
379 @tparam E ending iterator type
380 @tparam T result type
381 @tparam O binary reducer type
382 @tparam H chunk size type
383
384 @param first iterator to the beginning (inclusive)
385 @param last iterator to the end (exclusive)
386 @param init initial value of the reduction and the storage for the reduced result
387 @param bop binary operator that will be applied
388 @param chunk_size chunk size
389
390 The task spawns a subflow to perform parallel reduction over @c init and the elements in the range <tt>[first, last)</tt>. The reduced result is store in @c init. The runtime partitions the range into chunks of size @c chunk_size, where each chunk is processed by a worker.
391
392 Arguments are templated to enable stateful passing using std::reference_wrapper.
393
394 @return a Task handle
395 */
396 template <typename B, typename E, typename T, typename O, typename H = size_t>
397 Task reduce_guided(
398 B&& first, E&& last, T& init, O&& bop, H&& chunk_size = 1
399 );
400
401 /**
402 @brief constructs a STL-styled parallel-reduce task using the dynamic partition algorithm
403
404 @tparam B beginning iterator type
405 @tparam E ending iterator type
406 @tparam T result type
407 @tparam O binary reducer type
408 @tparam H chunk size type
409
410 @param first iterator to the beginning (inclusive)
411 @param last iterator to the end (exclusive)
412 @param init initial value of the reduction and the storage for the reduced result
413 @param bop binary operator that will be applied
414 @param chunk_size chunk size
415
416 The task spawns a subflow to perform parallel reduction over @c init and the elements in the range <tt>[first, last)</tt>. The reduced result is store in @c init. The runtime partitions the range into chunks of size @c chunk_size, where each chunk is processed by a worker.
417
418 Arguments are templated to enable stateful passing using std::reference_wrapper.
419
420 @return a Task handle
421 */
422 template <typename B, typename E, typename T, typename O, typename H = size_t>
423 Task reduce_dynamic(
424 B&& first, E&& last, T& init, O&& bop, H&& chunk_size = 1
425 );
426
427 /**
428 @brief constructs a STL-styled parallel-reduce task using the static partition algorithm
429
430 @tparam B beginning iterator type
431 @tparam E ending iterator type
432 @tparam T result type
433 @tparam O binary reducer type
434 @tparam H chunk size type
435
436 @param first iterator to the beginning (inclusive)
437 @param last iterator to the end (exclusive)
438 @param init initial value of the reduction and the storage for the reduced result
439 @param bop binary operator that will be applied
440 @param chunk_size chunk size
441
442 The task spawns a subflow to perform parallel reduction over @c init and the elements in the range <tt>[first, last)</tt>. The reduced result is store in @c init. The runtime partitions the range into chunks of size @c chunk_size, where each chunk is processed by a worker.
443
444 Arguments are templated to enable stateful passing using std::reference_wrapper.
445
446 @return a Task handle
447 */
448 template <typename B, typename E, typename T, typename O, typename H = size_t>
449 Task reduce_static(
450 B&& first, E&& last, T& init, O&& bop, H&& chunk_size = 0
451 );
452
453 // ------------------------------------------------------------------------
454 // transfrom and reduction
455 // ------------------------------------------------------------------------
456
457 /**
458 @brief constructs a STL-styled parallel transform-reduce task
459
460 @tparam B beginning iterator type
461 @tparam E ending iterator type
462 @tparam T result type
463 @tparam BOP binary reducer type
464 @tparam UOP unary transformion type
465
466 @param first iterator to the beginning (inclusive)
467 @param last iterator to the end (exclusive)
468 @param init initial value of the reduction and the storage for the reduced result
469 @param bop binary operator that will be applied in unspecified order to the results of @c uop
470 @param uop unary operator that will be applied to transform each element in the range to the result type
471
472 @return a Task handle
473
474 The task spawns a subflow to perform parallel reduction over @c init and the transformed elements in the range <tt>[first, last)</tt>. The reduced result is store in @c init. The runtime partitions the range into chunks of the given chunk size, where each chunk is processed by a worker. By default, we employ the guided partition algorithm.
475
476 This method is equivalent to the parallel execution of the following loop:
477
478 @code{.cpp}
479 for(auto itr=first; itr!=last; itr++) {
480 init = bop(init, uop(*itr));
481 }
482 @endcode
483
484 Arguments are templated to enable stateful passing using std::reference_wrapper.
485 */
486 template <typename B, typename E, typename T, typename BOP, typename UOP>
487 Task transform_reduce(B&& first, E&& last, T& init, BOP&& bop, UOP&& uop);
488
489 /**
490 @brief constructs a STL-styled parallel transform-reduce task using the guided partition algorithm
491
492 @tparam B beginning iterator type
493 @tparam E ending iterator type
494 @tparam T result type
495 @tparam BOP binary reducer type
496 @tparam UOP unary transformion type
497 @tparam H chunk size type
498
499 @param first iterator to the beginning (inclusive)
500 @param last iterator to the end (exclusive)
501 @param init initial value of the reduction and the storage for the reduced result
502 @param bop binary operator that will be applied in unspecified order to the results of @c uop
503 @param uop unary operator that will be applied to transform each element in the range to the result type
504 @param chunk_size chunk size
505
506 @return a Task handle
507
508 The task spawns a subflow to perform parallel reduction over @c init and the transformed elements in the range <tt>[first, last)</tt>. The reduced result is store in @c init. The runtime partitions the range into chunks of size @c chunk_size, where each chunk is processed by a worker.
509
510 Arguments are templated to enable stateful passing using std::reference_wrapper.
511 */
512 template <typename B, typename E, typename T, typename BOP, typename UOP, typename H = size_t>
513 Task transform_reduce_guided(
514 B&& first, E&& last, T& init, BOP&& bop, UOP&& uop, H&& chunk_size = 1
515 );
516
517 /**
518 @brief constructs a STL-styled parallel transform-reduce task using the static partition algorithm
519
520 @tparam B beginning iterator type
521 @tparam E ending iterator type
522 @tparam T result type
523 @tparam BOP binary reducer type
524 @tparam UOP unary transformion type
525 @tparam H chunk size type
526
527 @param first iterator to the beginning (inclusive)
528 @param last iterator to the end (exclusive)
529 @param init initial value of the reduction and the storage for the reduced result
530 @param bop binary operator that will be applied in unspecified order to the results of @c uop
531 @param uop unary operator that will be applied to transform each element in the range to the result type
532 @param chunk_size chunk size
533
534 @return a Task handle
535
536 The task spawns a subflow to perform parallel reduction over @c init and the transformed elements in the range <tt>[first, last)</tt>. The reduced result is store in @c init. The runtime partitions the range into chunks of size @c chunk_size, where each chunk is processed by a worker.
537
538 Arguments are templated to enable stateful passing using std::reference_wrapper.
539 */
540 template <typename B, typename E, typename T, typename BOP, typename UOP, typename H = size_t>
541 Task transform_reduce_static(
542 B&& first, E&& last, T& init, BOP&& bop, UOP&& uop, H&& chunk_size = 0
543 );
544
545 /**
546 @brief constructs a STL-styled parallel transform-reduce task using the dynamic partition algorithm
547
548 @tparam B beginning iterator type
549 @tparam E ending iterator type
550 @tparam T result type
551 @tparam BOP binary reducer type
552 @tparam UOP unary transformion type
553 @tparam H chunk size type
554
555 @param first iterator to the beginning (inclusive)
556 @param last iterator to the end (exclusive)
557 @param init initial value of the reduction and the storage for the reduced result
558 @param bop binary operator that will be applied in unspecified order to the results of @c uop
559 @param uop unary operator that will be applied to transform each element in the range to the result type
560 @param chunk_size chunk size
561
562 @return a Task handle
563
564 The task spawns a subflow to perform parallel reduction over @c init and the transformed elements in the range <tt>[first, last)</tt>. The reduced result is store in @c init. The runtime partitions the range into chunks of size @c chunk_size, where each chunk is processed by a worker.
565
566 Arguments are templated to enable stateful passing using std::reference_wrapper.
567 */
568 template <typename B, typename E, typename T, typename BOP, typename UOP, typename H = size_t>
569 Task transform_reduce_dynamic(
570 B&& first, E&& last, T& init, BOP&& bop, UOP&& uop, H&& chunk_size = 1
571 );
572
573
574 protected:
575
576 /**
577 @brief constructs a flow builder with a graph
578 */
579 FlowBuilder(Graph& graph);
580
581 /**
582 @brief associated graph object
583 */
584 Graph& _graph;
585
586 private:
587
588 template <typename L>
589 void _linearize(L&);
590 };
591
592 // Constructor
FlowBuilder(Graph & graph)593 inline FlowBuilder::FlowBuilder(Graph& graph) :
594 _graph {graph} {
595 }
596
597 // Function: emplace
598 template <typename... C, std::enable_if_t<(sizeof...(C)>1), void>*>
emplace(C &&...cs)599 auto FlowBuilder::emplace(C&&... cs) {
600 return std::make_tuple(emplace(std::forward<C>(cs))...);
601 }
602
603 // Function: emplace
604 // emplaces a static task
605 template <typename C>
emplace(C && c)606 std::enable_if_t<is_static_task_v<C>, Task> FlowBuilder::emplace(C&& c) {
607 auto n = _graph.emplace_back(
608 nstd::in_place_type_t<Node::StaticWork>{}, std::forward<C>(c)
609 );
610 return Task(n);
611 }
612
613 // Function: emplace
614 // emplaces a dynamic task
615 template <typename C>
emplace(C && c)616 std::enable_if_t<is_dynamic_task_v<C>, Task> FlowBuilder::emplace(C&& c) {
617 auto n = _graph.emplace_back(
618 nstd::in_place_type_t<Node::DynamicWork>{}, std::forward<C>(c)
619 );
620 return Task(n);
621 }
622
623 // Function: emplace
624 // emplaces a condition task
625 template <typename C>
emplace(C && c)626 std::enable_if_t<is_condition_task_v<C>, Task> FlowBuilder::emplace(C&& c) {
627 auto n = _graph.emplace_back(
628 nstd::in_place_type_t<Node::ConditionWork>{}, std::forward<C>(c)
629 );
630 return Task(n);
631 }
632
633 #ifdef TF_ENABLE_CUDA
634 // Function: emplace
635 // emplaces a cudaflow task
636 template <typename C>
emplace(C && c)637 std::enable_if_t<is_cudaflow_task_v<C>, Task> FlowBuilder::emplace(C&& c) {
638 auto n = _graph.emplace_back(
639 nstd::in_place_type_t<Node::cudaFlowWork>{}, std::forward<C>(c)
640 );
641 return Task(n);
642 }
643 #endif
644
645 // Function: composed_of
composed_of(Taskflow & taskflow)646 inline Task FlowBuilder::composed_of(Taskflow& taskflow) {
647 auto node = _graph.emplace_back(
648 nstd::in_place_type_t<Node::ModuleWork>{}, &taskflow
649 );
650 return Task(node);
651 }
652
653 // Function: placeholder
placeholder()654 inline Task FlowBuilder::placeholder() {
655 auto node = _graph.emplace_back();
656 return Task(node);
657 }
658
659 // Procedure: _linearize
660 template <typename L>
_linearize(L & keys)661 void FlowBuilder::_linearize(L& keys) {
662
663 auto itr = keys.begin();
664 auto end = keys.end();
665
666 if(itr == end) {
667 return;
668 }
669
670 auto nxt = itr;
671
672 for(++nxt; nxt != end; ++nxt, ++itr) {
673 itr->_node->_precede(nxt->_node);
674 }
675 }
676
677 // Procedure: linearize
linearize(std::vector<Task> & keys)678 inline void FlowBuilder::linearize(std::vector<Task>& keys) {
679 _linearize(keys);
680 }
681
682 // Procedure: linearize
linearize(std::initializer_list<Task> keys)683 inline void FlowBuilder::linearize(std::initializer_list<Task> keys) {
684 _linearize(keys);
685 }
686
687 // ----------------------------------------------------------------------------
688
689 /**
690 @class Subflow
691
692 @brief building methods of a subflow graph in dynamic tasking
693
694 By default, a subflow automatically joins its parent node. You may explicitly
695 join or detach a subflow by calling Subflow::join or Subflow::detach.
696
697 */
698 class Subflow : public FlowBuilder {
699
700 friend class Executor;
701 friend class FlowBuilder;
702
703 public:
704
705 /**
706 @brief enables the subflow to join its parent task
707
708 Performs an immediate action to join the subflow. Once the subflow is joined,
709 it is considered finished and you may not modify the subflow anymore.
710 */
711 void join();
712
713 /**
714 @brief enables the subflow to detach from its parent task
715
716 Performs an immediate action to detach the subflow. Once the subflow is detached,
717 it is considered finished and you may not modify the subflow anymore.
718 */
719 void detach();
720
721 /**
722 @brief queries if the subflow is joinable
723
724 When a subflow is joined or detached, it becomes not joinable.
725 */
726 bool joinable() const;
727
728 private:
729
730 Subflow(Executor&, Node*, Graph&);
731
732 Executor& _executor;
733 Node* _parent;
734
735 bool _joinable {true};
736 };
737
738 // Constructor
Subflow(Executor & executor,Node * parent,Graph & graph)739 inline Subflow::Subflow(Executor& executor, Node* parent, Graph& graph) :
740 FlowBuilder {graph},
741 _executor {executor},
742 _parent {parent} {
743 }
744
745 // Function: joined
joinable() const746 inline bool Subflow::joinable() const {
747 return _joinable;
748 }
749
750 // ----------------------------------------------------------------------------
751 // Legacy code
752 // ----------------------------------------------------------------------------
753
754 using SubflowBuilder = Subflow;
755
756 } // end of namespace tf. ---------------------------------------------------
757
758
759