| Taskflow: A General-purpose Task-parallel Programming System

Loading...
Searching...
No Matches
task_group.hpp
1#pragma once
2
3#include "executor.hpp"
4
5 namespace tf {
6
7// ------------------------------------------------------------------------------------------------
8// class: TaskGroup
9// ------------------------------------------------------------------------------------------------
10
61 class TaskGroup {
62
63 friend class Executor;
64
65 public:
66
67 // ----------------------------------------------------------------------------------------------
68 // deleted members
69 // ----------------------------------------------------------------------------------------------
70
74 TaskGroup(const TaskGroup&) = delete;
75
79 TaskGroup(TaskGroup&&) = delete;
80
84 TaskGroup& operator = (TaskGroup&&) = delete;
85
89 TaskGroup& operator = (const TaskGroup&) = delete;
90
103 Executor& executor();
104
105 // ----------------------------------------------------------------------------------------------
106 // async methods
107 // ----------------------------------------------------------------------------------------------
108
141 template <typename F>
142 auto async(F&& f);
143
165 template <TaskParamsLike P, typename F>
166 auto async(P&& params, F&& f);
167
168 // ----------------------------------------------------------------------------------------------
169 // silent async methods
170 // ----------------------------------------------------------------------------------------------
171
194 template <typename F>
195 void silent_async(F&& f);
196
217 template <TaskParamsLike P, typename F>
218 void silent_async(P&& params, F&& f);
219
220 // ----------------------------------------------------------------------------------------------
221 // dependent async methods
222 // ----------------------------------------------------------------------------------------------
223
259 template <typename F, AsyncTaskHandleLike... Tasks>
260 auto dependent_async(F&& func, Tasks&&... tasks);
261
301 template <TaskParamsLike P, typename F, AsyncTaskHandleLike... Tasks>
302 auto dependent_async(P&& params, F&& func, Tasks&&... tasks);
303
342 template <typename F, std::input_iterator I>
343 auto dependent_async(F&& func, I first, I last);
344
387 template <TaskParamsLike P, typename F, std::input_iterator I>
388 auto dependent_async(P&& params, F&& func, I first, I last);
389
390
391 // ----------------------------------------------------------------------------------------------
392 // silent dependent async methods
393 // ----------------------------------------------------------------------------------------------
394
423 template <typename F, AsyncTaskHandleLike... Tasks>
424 tf::AsyncTask silent_dependent_async(F&& func, Tasks&&... tasks);
425
459 template <TaskParamsLike P, typename F, AsyncTaskHandleLike... Tasks>
460 tf::AsyncTask silent_dependent_async(P&& params, F&& func, Tasks&&... tasks);
461
495 template <typename F, std::input_iterator I>
496 tf::AsyncTask silent_dependent_async(F&& func, I first, I last);
497
534 template <TaskParamsLike P, typename F, std::input_iterator I>
535 tf::AsyncTask silent_dependent_async(P&& params, F&& func, I first, I last);
536
537
538 // ----------------------------------------------------------------------------------------------
539 // cooperative execution methods
540 // ----------------------------------------------------------------------------------------------
541
574 void corun();
575
632 void cancel();
633
657 bool is_cancelled();
658
683 size_t size() const;
684
685 private:
686
690 explicit TaskGroup(Executor&, Worker&);
691
695 Executor& _executor;
696
700 Worker& _worker;
701
705 NodeBase _node_base;
706};
707
708// constructor
709 inline TaskGroup::TaskGroup(Executor& executor, Worker& worker) :
710 _executor {executor},
711 _worker {worker},
712 _node_base {NSTATE::IMPLICITLY_ANCHORED, ESTATE::NONE, nullptr, 0} {
713}
714
715// Function: executor
716 inline Executor& TaskGroup::executor() {
717 return _executor;
718}
719
720// Function: corun
721 inline void TaskGroup::corun() {
722 {
723 ExplicitAnchorGuard anchor(&_node_base);
724 _executor._corun_until(_worker, [this] () -> bool {
725 return _node_base._join_counter.load(std::memory_order_acquire) == 0;
726 });
727 }
728 _node_base._rethrow_exception();
729}
730
731// Function: cancel
732 inline void TaskGroup::cancel() {
733 _node_base._estate.fetch_or(ESTATE::CANCELLED, std::memory_order_relaxed);
734}
735
736// Function: is_cancelled
737 inline bool TaskGroup::is_cancelled() {
738 return _node_base._estate.load(std::memory_order_relaxed) & ESTATE::CANCELLED;
739}
740
741// Function: size
742 inline size_t TaskGroup::size() const {
743 return _node_base._join_counter.load(std::memory_order_relaxed);
744}
745
746// ------------------------------------------------------------------------------------------------
747// TaskGroup::silent_async
748// ------------------------------------------------------------------------------------------------
749
750// Function: silent_async
751 template <typename F>
752 void TaskGroup::silent_async(F&& f) {
753 silent_async(DefaultTaskParams{}, std::forward<F>(f));
754}
755
756// Function: silent_async
757 template <TaskParamsLike P, typename F>
758 void TaskGroup::silent_async(P&& params, F&& f) {
759 _node_base._join_counter.fetch_add(1, std::memory_order_relaxed);
760 _executor._silent_async(
761 std::forward<P>(params), std::forward<F>(f), nullptr, &_node_base
762 );
763}
764
765// ------------------------------------------------------------------------------------------------
766// TaskGroup::async
767// ------------------------------------------------------------------------------------------------
768
769// Function: async
770 template <typename F>
771 auto TaskGroup::async(F&& f) {
772 return async(DefaultTaskParams{}, std::forward<F>(f));
773}
774
775// Function: async
776 template <TaskParamsLike P, typename F>
777 auto TaskGroup::async(P&& params, F&& f) {
778 _node_base._join_counter.fetch_add(1, std::memory_order_relaxed);
779 return _executor._async(
780 std::forward<P>(params), std::forward<F>(f), nullptr, &_node_base
781 );
782}
783
784// ------------------------------------------------------------------------------------------------
785// silent dependent async
786// ------------------------------------------------------------------------------------------------
787
788// Function: silent_dependent_async
789 template <typename F, AsyncTaskHandleLike... Tasks>
790 tf::AsyncTask TaskGroup::silent_dependent_async(F&& func, Tasks&&... tasks) {
791 return silent_dependent_async(
792 DefaultTaskParams{}, std::forward<F>(func), std::forward<Tasks>(tasks)...
793 );
794}
795
796// Function: silent_dependent_async
797 template <TaskParamsLike P, typename F, AsyncTaskHandleLike... Tasks>
798 tf::AsyncTask TaskGroup::silent_dependent_async(
799 P&& params, F&& func, Tasks&&... tasks
800){
801 std::array<AsyncTask*, sizeof...(Tasks)> array = { (&tasks)... };
802 return silent_dependent_async(
803 std::forward<P>(params), std::forward<F>(func), array.begin(), array.end()
804 );
805}
806
807// Function: silent_dependent_async
808 template <typename F, std::input_iterator I>
809 tf::AsyncTask TaskGroup::silent_dependent_async(F&& func, I first, I last) {
810 return silent_dependent_async(DefaultTaskParams{}, std::forward<F>(func), first, last);
811}
812
813// Function: silent_dependent_async
814 template <TaskParamsLike P, typename F, std::input_iterator I>
815 tf::AsyncTask TaskGroup::silent_dependent_async(
816 P&& params, F&& func, I first, I last
817) {
818 _node_base._join_counter.fetch_add(1, std::memory_order_relaxed);
819 return _executor._silent_dependent_async(
820 std::forward<P>(params), std::forward<F>(func), first, last, nullptr, &_node_base
821 );
822}
823
824// ------------------------------------------------------------------------------------------------
825// dependent async
826// ------------------------------------------------------------------------------------------------
827
828// Function: dependent_async
829 template <typename F, AsyncTaskHandleLike... Tasks>
830 auto TaskGroup::dependent_async(F&& func, Tasks&&... tasks) {
831 return dependent_async(DefaultTaskParams{}, std::forward<F>(func), std::forward<Tasks>(tasks)...);
832}
833
834// Function: dependent_async
835 template <TaskParamsLike P, typename F, AsyncTaskHandleLike... Tasks>
836 auto TaskGroup::dependent_async(P&& params, F&& func, Tasks&&... tasks) {
837 std::array<AsyncTask*, sizeof...(Tasks)> array = { (&tasks)... };
838 return dependent_async(
839 std::forward<P>(params), std::forward<F>(func), array.begin(), array.end()
840 );
841}
842
843// Function: dependent_async
844 template <typename F, std::input_iterator I>
845 auto TaskGroup::dependent_async(F&& func, I first, I last) {
846 return dependent_async(DefaultTaskParams{}, std::forward<F>(func), first, last);
847}
848
849// Function: dependent_async
850 template <TaskParamsLike P, typename F, std::input_iterator I>
851 auto TaskGroup::dependent_async(P&& params, F&& func, I first, I last) {
852 _node_base._join_counter.fetch_add(1, std::memory_order_relaxed);
853 return _executor._dependent_async(
854 std::forward<P>(params), std::forward<F>(func), first, last, nullptr, &_node_base
855 );
856}
857
858// ----------------------------------------------------------------------------
859// Executor Forward Declaration
860// ----------------------------------------------------------------------------
861
862// Procedure: task_group
863 inline TaskGroup Executor::task_group() {
864 Worker* w = this_worker();
865 if(w == nullptr) {
866 TF_THROW("task_group can only created by a worker of the executor");
867 }
868 return TaskGroup(*this, *w);
869}
870
871
872} // end of namespace tf -----------------------------------------------------
tf::AsyncTask
class to hold a dependent asynchronous task with shared ownership
Definition async_task.hpp:45
tf::DefaultTaskParams
class to create an empty task parameter for compile-time optimization
Definition graph.hpp:191
tf::Executor
class to create an executor
Definition executor.hpp:62
tf::Executor::task_group
TaskGroup task_group()
creates a task group that executes a collection of asynchronous tasks
Definition task_group.hpp:863
tf::Executor::this_worker
Worker * this_worker()
queries pointer to the calling worker if it belongs to this executor, otherwise returns nullptr
tf::TaskGroup
class to create a task group from a task
Definition task_group.hpp:61
tf::TaskGroup::dependent_async
auto dependent_async(F &&func, Tasks &&... tasks)
runs the given function asynchronously when the given predecessors finish
Definition task_group.hpp:830
tf::TaskGroup::corun
void corun()
corun all tasks spawned by this task group with other workers
Definition task_group.hpp:721
tf::TaskGroup::cancel
void cancel()
cancel all tasks in this task group
Definition task_group.hpp:732
tf::TaskGroup::size
size_t size() const
queries the number of tasks currently in this task group
Definition task_group.hpp:742
tf::TaskGroup::silent_dependent_async
tf::AsyncTask silent_dependent_async(F &&func, Tasks &&... tasks)
runs the given function asynchronously when the given predecessors finish
Definition task_group.hpp:790
tf::TaskGroup::async
auto async(F &&f)
runs the given callable asynchronously
Definition task_group.hpp:771
tf::TaskGroup::operator=
TaskGroup & operator=(TaskGroup &&)=delete
disabled copy assignment
tf::TaskGroup::is_cancelled
bool is_cancelled()
queries if the task group has been cancelled
Definition task_group.hpp:737
tf::TaskGroup::TaskGroup
TaskGroup(TaskGroup &&)=delete
disabled move constructor
tf::TaskGroup::TaskGroup
TaskGroup(const TaskGroup &)=delete
disabled copy constructor
tf::TaskGroup::executor
Executor & executor()
obtains the executor that creates this task group
Definition task_group.hpp:716
tf::TaskGroup::silent_async
void silent_async(F &&f)
runs the given function asynchronously without returning any future object
Definition task_group.hpp:752
tf::Worker
class to create a worker in an executor
Definition worker.hpp:55
tf::AsyncTaskHandleLike
concept to check if a type is a tf::AsyncTask
Definition async_task.hpp:314
tf::TaskParamsLike
concept that determines if a type is a task parameter type
Definition graph.hpp:202
tf
taskflow namespace
Definition small_vector.hpp:20