Taskflow  3.2.0-Master-Branch
Loading...
Searching...
No Matches
task.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "graph.hpp"
4
10namespace tf {
11
12// ----------------------------------------------------------------------------
13// Task Types
14// ----------------------------------------------------------------------------
15
21enum class TaskType : int {
23 PLACEHOLDER = 0,
29 STATIC,
31 DYNAMIC,
37 MODULE,
39 ASYNC,
41 RUNTIME,
44};
45
50inline constexpr std::array<TaskType, 10> TASK_TYPES = {
61};
62
81inline const char* to_string(TaskType type) {
82
83 const char* val;
84
85 switch(type) {
86 case TaskType::PLACEHOLDER: val = "placeholder"; break;
87 case TaskType::CUDAFLOW: val = "cudaflow"; break;
88 case TaskType::SYCLFLOW: val = "syclflow"; break;
89 case TaskType::STATIC: val = "static"; break;
90 case TaskType::DYNAMIC: val = "subflow"; break;
91 case TaskType::CONDITION: val = "condition"; break;
92 case TaskType::MULTI_CONDITION: val = "multi_condition"; break;
93 case TaskType::MODULE: val = "module"; break;
94 case TaskType::ASYNC: val = "async"; break;
95 case TaskType::RUNTIME: val = "runtime"; break;
96 default: val = "undefined"; break;
97 }
98
99 return val;
100}
101
102// ----------------------------------------------------------------------------
103// Task Traits
104// ----------------------------------------------------------------------------
105
111template <typename C>
112constexpr bool is_static_task_v =
116
122template <typename C>
124
130template <typename C>
132
139template <typename C>
142
149template <typename C>
152
159template <typename C>
161
168template <typename C>
170
171// ----------------------------------------------------------------------------
172// Task
173// ----------------------------------------------------------------------------
174
187class Task {
188
189 friend class FlowBuilder;
190 friend class Runtime;
191 friend class Taskflow;
192 friend class TaskView;
193 friend class Executor;
194
195 public:
196
200 Task() = default;
201
205 Task(const Task& other);
206
210 Task& operator = (const Task&);
211
216
220 bool operator == (const Task& rhs) const;
221
225 bool operator != (const Task& rhs) const;
226
230 const std::string& name() const;
231
235 size_t num_successors() const;
236
240 size_t num_dependents() const;
241
245 size_t num_strong_dependents() const;
246
250 size_t num_weak_dependents() const;
251
259 Task& name(const std::string& name);
260
271 template <typename C>
272 Task& work(C&& callable);
273
282 template <typename T>
283 Task& composed_of(T& object);
284
294 template <typename... Ts>
295 Task& precede(Ts&&... tasks);
296
306 template <typename... Ts>
307 Task& succeed(Ts&&... tasks);
308
312 Task& release(Semaphore& semaphore);
313
317 Task& acquire(Semaphore& semaphore);
318
348 Task& data(void* data);
349
353 void reset();
354
358 void reset_work();
359
363 bool empty() const;
364
368 bool has_work() const;
369
373 template <typename V>
374 void for_each_successor(V&& visitor) const;
375
379 template <typename V>
380 void for_each_dependent(V&& visitor) const;
381
385 size_t hash_value() const;
386
390 TaskType type() const;
391
395 void dump(std::ostream& ostream) const;
396
400 void* data() const;
401
402
403 private:
404
405 Task(Node*);
406
407 Node* _node {nullptr};
408};
409
410// Constructor
411inline Task::Task(Node* node) : _node {node} {
412}
413
414// Constructor
415inline Task::Task(const Task& rhs) : _node {rhs._node} {
416}
417
418// Function: precede
419template <typename... Ts>
420Task& Task::precede(Ts&&... tasks) {
421 (_node->_precede(tasks._node), ...);
422 //_precede(std::forward<Ts>(tasks)...);
423 return *this;
424}
425
426// Function: succeed
427template <typename... Ts>
428Task& Task::succeed(Ts&&... tasks) {
429 (tasks._node->_precede(_node), ...);
430 //_succeed(std::forward<Ts>(tasks)...);
431 return *this;
432}
433
434// Function: composed_of
435template <typename T>
437 _node->_handle.emplace<Node::Module>(object);
438 return *this;
439}
440
441// Operator =
442inline Task& Task::operator = (const Task& rhs) {
443 _node = rhs._node;
444 return *this;
445}
446
447// Operator =
449 _node = ptr;
450 return *this;
451}
452
453// Operator ==
454inline bool Task::operator == (const Task& rhs) const {
455 return _node == rhs._node;
456}
457
458// Operator !=
459inline bool Task::operator != (const Task& rhs) const {
460 return _node != rhs._node;
461}
462
463// Function: name
464inline Task& Task::name(const std::string& name) {
465 _node->_name = name;
466 return *this;
467}
468
469// Function: acquire
471 if(!_node->_semaphores) {
472 _node->_semaphores = std::make_unique<Node::Semaphores>();
473 }
474 _node->_semaphores->to_acquire.push_back(&s);
475 return *this;
476}
477
478// Function: release
480 if(!_node->_semaphores) {
481 //_node->_semaphores.emplace();
482 _node->_semaphores = std::make_unique<Node::Semaphores>();
483 }
484 _node->_semaphores->to_release.push_back(&s);
485 return *this;
486}
487
488// Procedure: reset
489inline void Task::reset() {
490 _node = nullptr;
491}
492
493// Procedure: reset_work
494inline void Task::reset_work() {
495 _node->_handle.emplace<std::monostate>();
496}
497
498// Function: name
499inline const std::string& Task::name() const {
500 return _node->_name;
501}
502
503// Function: num_dependents
504inline size_t Task::num_dependents() const {
505 return _node->num_dependents();
506}
507
508// Function: num_strong_dependents
509inline size_t Task::num_strong_dependents() const {
510 return _node->num_strong_dependents();
511}
512
513// Function: num_weak_dependents
514inline size_t Task::num_weak_dependents() const {
515 return _node->num_weak_dependents();
516}
517
518// Function: num_successors
519inline size_t Task::num_successors() const {
520 return _node->num_successors();
521}
522
523// Function: empty
524inline bool Task::empty() const {
525 return _node == nullptr;
526}
527
528// Function: has_work
529inline bool Task::has_work() const {
530 return _node ? _node->_handle.index() != 0 : false;
531}
532
533// Function: task_type
534inline TaskType Task::type() const {
535 switch(_node->_handle.index()) {
536 case Node::PLACEHOLDER: return TaskType::PLACEHOLDER;
537 case Node::STATIC: return TaskType::STATIC;
538 case Node::DYNAMIC: return TaskType::DYNAMIC;
539 case Node::CONDITION: return TaskType::CONDITION;
540 case Node::MULTI_CONDITION: return TaskType::MULTI_CONDITION;
541 case Node::MODULE: return TaskType::MODULE;
542 case Node::ASYNC: return TaskType::ASYNC;
543 case Node::SILENT_ASYNC: return TaskType::ASYNC;
544 case Node::CUDAFLOW: return TaskType::CUDAFLOW;
545 case Node::SYCLFLOW: return TaskType::SYCLFLOW;
546 case Node::RUNTIME: return TaskType::RUNTIME;
547 default: return TaskType::UNDEFINED;
548 }
549}
550
551// Function: for_each_successor
552template <typename V>
553void Task::for_each_successor(V&& visitor) const {
554 for(size_t i=0; i<_node->_successors.size(); ++i) {
555 visitor(Task(_node->_successors[i]));
556 }
557}
558
559// Function: for_each_dependent
560template <typename V>
561void Task::for_each_dependent(V&& visitor) const {
562 for(size_t i=0; i<_node->_dependents.size(); ++i) {
563 visitor(Task(_node->_dependents[i]));
564 }
565}
566
567// Function: hash_value
568inline size_t Task::hash_value() const {
569 return std::hash<Node*>{}(_node);
570}
571
572// Procedure: dump
573inline void Task::dump(std::ostream& os) const {
574 os << "task ";
575 if(name().empty()) os << _node;
576 else os << name();
577 os << " [type=" << to_string(type()) << ']';
578}
579
580// Function: work
581template <typename C>
583
584 if constexpr(is_static_task_v<C>) {
585 _node->_handle.emplace<Node::Static>(std::forward<C>(c));
586 }
587 else if constexpr(is_dynamic_task_v<C>) {
588 _node->_handle.emplace<Node::Dynamic>(std::forward<C>(c));
589 }
590 else if constexpr(is_condition_task_v<C>) {
591 _node->_handle.emplace<Node::Condition>(std::forward<C>(c));
592 }
593 else if constexpr(is_multi_condition_task_v<C>) {
594 _node->_handle.emplace<Node::MultiCondition>(std::forward<C>(c));
595 }
596 else if constexpr(is_cudaflow_task_v<C>) {
597 _node->_handle.emplace<Node::cudaFlow>(std::forward<C>(c));
598 }
599 else if constexpr(is_runtime_task_v<C>) {
600 _node->_handle.emplace<Node::Runtime>(std::forward<C>(c));
601 }
602 else {
603 static_assert(dependent_false_v<C>, "invalid task callable");
604 }
605 return *this;
606}
607
608// Function: name
609inline void* Task::data() const {
610 return _node->_data;
611}
612
613// Function: name
614inline Task& Task::data(void* data) {
615 _node->_data = data;
616 return *this;
617}
618
619// ----------------------------------------------------------------------------
620// global ostream
621// ----------------------------------------------------------------------------
622
626inline std::ostream& operator << (std::ostream& os, const Task& task) {
627 task.dump(os);
628 return os;
629}
630
631// ----------------------------------------------------------------------------
632
638class TaskView {
639
640 friend class Executor;
641
642 public:
643
647 const std::string& name() const;
648
652 size_t num_successors() const;
653
657 size_t num_dependents() const;
658
662 size_t num_strong_dependents() const;
663
667 size_t num_weak_dependents() const;
668
672 template <typename V>
673 void for_each_successor(V&& visitor) const;
674
678 template <typename V>
679 void for_each_dependent(V&& visitor) const;
680
684 TaskType type() const;
685
689 size_t hash_value() const;
690
691 private:
692
693 TaskView(const Node&);
694 TaskView(const TaskView&) = default;
695
696 const Node& _node;
697};
698
699// Constructor
700inline TaskView::TaskView(const Node& node) : _node {node} {
701}
702
703// Function: name
704inline const std::string& TaskView::name() const {
705 return _node._name;
706}
707
708// Function: num_dependents
709inline size_t TaskView::num_dependents() const {
710 return _node.num_dependents();
711}
712
713// Function: num_strong_dependents
714inline size_t TaskView::num_strong_dependents() const {
715 return _node.num_strong_dependents();
716}
717
718// Function: num_weak_dependents
719inline size_t TaskView::num_weak_dependents() const {
720 return _node.num_weak_dependents();
721}
722
723// Function: num_successors
724inline size_t TaskView::num_successors() const {
725 return _node.num_successors();
726}
727
728// Function: type
729inline TaskType TaskView::type() const {
730 switch(_node._handle.index()) {
731 case Node::PLACEHOLDER: return TaskType::PLACEHOLDER;
732 case Node::STATIC: return TaskType::STATIC;
733 case Node::DYNAMIC: return TaskType::DYNAMIC;
734 case Node::CONDITION: return TaskType::CONDITION;
735 case Node::MULTI_CONDITION: return TaskType::MULTI_CONDITION;
736 case Node::MODULE: return TaskType::MODULE;
737 case Node::ASYNC: return TaskType::ASYNC;
738 case Node::SILENT_ASYNC: return TaskType::ASYNC;
739 case Node::CUDAFLOW: return TaskType::CUDAFLOW;
740 case Node::SYCLFLOW: return TaskType::SYCLFLOW;
741 case Node::RUNTIME: return TaskType::RUNTIME;
742 default: return TaskType::UNDEFINED;
743 }
744}
745
746// Function: hash_value
747inline size_t TaskView::hash_value() const {
748 return std::hash<const Node*>{}(&_node);
749}
750
751// Function: for_each_successor
752template <typename V>
753void TaskView::for_each_successor(V&& visitor) const {
754 for(size_t i=0; i<_node._successors.size(); ++i) {
755 visitor(TaskView(_node._successors[i]));
756 }
757}
758
759// Function: for_each_dependent
760template <typename V>
761void TaskView::for_each_dependent(V&& visitor) const {
762 for(size_t i=0; i<_node._dependents.size(); ++i) {
763 visitor(TaskView(_node._dependents[i]));
764 }
765}
766
767} // end of namespace tf. ---------------------------------------------------
768
769namespace std {
770
776template <>
777struct hash<tf::Task> {
778 auto operator() (const tf::Task& task) const noexcept {
779 return task.hash_value();
780 }
781};
782
788template <>
789struct hash<tf::TaskView> {
790 auto operator() (const tf::TaskView& task_view) const noexcept {
791 return task_view.hash_value();
792 }
793};
794
795} // end of namespace std ----------------------------------------------------
796
797
798
class to create an executor for running a taskflow graph
Definition executor.hpp:50
class to build a task dependency graph
Definition flow_builder.hpp:21
class to create a runtime object used by a runtime task
Definition graph.hpp:150
class to create a semophore object for building a concurrency constraint
Definition semaphore.hpp:68
class to access task information from the observer interface
Definition task.hpp:638
void for_each_successor(V &&visitor) const
applies an visitor callable to each successor of the task
Definition task.hpp:753
void for_each_dependent(V &&visitor) const
applies an visitor callable to each dependents of the task
Definition task.hpp:761
TaskType type() const
queries the task type
Definition task.hpp:729
size_t hash_value() const
obtains a hash value of the underlying node
Definition task.hpp:747
size_t num_strong_dependents() const
queries the number of strong dependents of the task
Definition task.hpp:714
const std::string & name() const
queries the name of the task
Definition task.hpp:704
size_t num_dependents() const
queries the number of predecessors of the task
Definition task.hpp:709
size_t num_weak_dependents() const
queries the number of weak dependents of the task
Definition task.hpp:719
size_t num_successors() const
queries the number of successors of the task
Definition task.hpp:724
class to create a task handle over a node in a taskflow graph
Definition task.hpp:187
Task & acquire(Semaphore &semaphore)
makes the task acquire this semaphore
Definition task.hpp:470
const std::string & name() const
queries the name of the task
Definition task.hpp:499
size_t num_successors() const
queries the number of successors of the task
Definition task.hpp:519
size_t hash_value() const
obtains a hash value of the underlying node
Definition task.hpp:568
Task & release(Semaphore &semaphore)
makes the task release this semaphore
Definition task.hpp:479
Task & work(C &&callable)
assigns a callable
Definition task.hpp:582
void reset()
resets the task handle to null
Definition task.hpp:489
void * data() const
queries pointer to user data
Definition task.hpp:609
void dump(std::ostream &ostream) const
dumps the task through an output stream
Definition task.hpp:573
Task & succeed(Ts &&... tasks)
adds precedence links from other tasks to this
Definition task.hpp:428
void for_each_dependent(V &&visitor) const
applies an visitor callable to each dependents of the task
Definition task.hpp:561
Task()=default
constructs an empty task
bool empty() const
queries if the task handle points to a task node
Definition task.hpp:524
Task & precede(Ts &&... tasks)
adds precedence links from this to other tasks
Definition task.hpp:420
size_t num_dependents() const
queries the number of predecessors of the task
Definition task.hpp:504
Task & composed_of(T &object)
creates a module task from a taskflow
Definition task.hpp:436
size_t num_strong_dependents() const
queries the number of strong dependents of the task
Definition task.hpp:509
bool operator==(const Task &rhs) const
compares if two tasks are associated with the same graph node
Definition task.hpp:454
Task & operator=(const Task &)
replaces the contents with a copy of the other task
Definition task.hpp:442
void reset_work()
resets the associated work to a placeholder
Definition task.hpp:494
TaskType type() const
returns the task type
Definition task.hpp:534
size_t num_weak_dependents() const
queries the number of weak dependents of the task
Definition task.hpp:514
bool operator!=(const Task &rhs) const
compares if two tasks are not associated with the same graph node
Definition task.hpp:459
bool has_work() const
queries if the task has a work assigned
Definition task.hpp:529
void for_each_successor(V &&visitor) const
applies an visitor callable to each successor of the task
Definition task.hpp:553
class to create a taskflow object
Definition core/taskflow.hpp:73
T forward(T... args)
graph include file
taskflow namespace
Definition small_vector.hpp:27
constexpr bool is_condition_task_v
determines if a callable is a condition task
Definition task.hpp:131
constexpr bool is_static_task_v
determines if a callable is a static task
Definition task.hpp:112
TaskType
enumeration of all task types
Definition task.hpp:21
@ UNDEFINED
undefined task type (for internal use only)
@ DYNAMIC
dynamic (subflow) task type
@ MODULE
module task type
@ CUDAFLOW
cudaFlow task type
@ MULTI_CONDITION
multi-condition task type
@ CONDITION
condition task type
@ SYCLFLOW
syclFlow task type
@ ASYNC
asynchronous task type
@ PLACEHOLDER
placeholder task type
@ RUNTIME
runtime task type
@ STATIC
static task type
const char * to_string(TaskType type)
convert a task type to a human-readable string
Definition task.hpp:81
constexpr bool is_dynamic_task_v
determines if a callable is a dynamic task
Definition task.hpp:123
constexpr bool is_syclflow_task_v
determines if a callable is a syclFlow task
Definition task.hpp:160
constexpr bool is_multi_condition_task_v
determines if a callable is a multi-condition task
Definition task.hpp:140
std::ostream & operator<<(std::ostream &os, const Task &task)
overload of ostream inserter operator for cudaTask
Definition task.hpp:626
constexpr bool is_cudaflow_task_v
determines if a callable is a cudaFlow task
Definition task.hpp:150
constexpr bool is_runtime_task_v
determines if a callable is a runtime task
Definition task.hpp:169
T operator()(T... args)