Loading...
Searching...
No Matches
task_group.hpp
1#pragma once
2
3#include "executor.hpp"
4
5namespace tf {
6
7// ------------------------------------------------------------------------------------------------
8// class: TaskGroup
9// ------------------------------------------------------------------------------------------------
10
61class 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
85
89 TaskGroup& operator = (const TaskGroup&) = delete;
90
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
709inline 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
717 return _executor;
718}
719
720// Function: corun
721inline 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
732inline void TaskGroup::cancel() {
733 _node_base._estate.fetch_or(ESTATE::CANCELLED, std::memory_order_relaxed);
734}
735
736// Function: is_cancelled
738 return _node_base._estate.load(std::memory_order_relaxed) & ESTATE::CANCELLED;
739}
740
741// Function: size
742inline 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
751template <typename F>
753 silent_async(DefaultTaskParams{}, std::forward<F>(f));
754}
755
756// Function: silent_async
757template <TaskParamsLike P, typename F>
758void 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
770template <typename F>
771auto TaskGroup::async(F&& f) {
772 return async(DefaultTaskParams{}, std::forward<F>(f));
773}
774
775// Function: async
776template <TaskParamsLike P, typename F>
777auto 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
789template <typename F, AsyncTaskHandleLike... Tasks>
792 DefaultTaskParams{}, std::forward<F>(func), std::forward<Tasks>(tasks)...
793 );
794}
795
796// Function: silent_dependent_async
797template <TaskParamsLike P, typename F, AsyncTaskHandleLike... Tasks>
799 P&& params, F&& func, Tasks&&... tasks
800){
801 std::array<AsyncTask*, sizeof...(Tasks)> array = { (&tasks)... };
803 std::forward<P>(params), std::forward<F>(func), array.begin(), array.end()
804 );
805}
806
807// Function: silent_dependent_async
808template <typename F, std::input_iterator I>
810 return silent_dependent_async(DefaultTaskParams{}, std::forward<F>(func), first, last);
811}
812
813// Function: silent_dependent_async
814template <TaskParamsLike P, typename F, std::input_iterator I>
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
829template <typename F, AsyncTaskHandleLike... Tasks>
830auto 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
835template <TaskParamsLike P, typename F, AsyncTaskHandleLike... Tasks>
836auto 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
844template <typename F, std::input_iterator I>
845auto 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
850template <TaskParamsLike P, typename F, std::input_iterator I>
851auto 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
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 -----------------------------------------------------
class to hold a dependent asynchronous task with shared ownership
Definition async_task.hpp:45
class to create an empty task parameter for compile-time optimization
Definition graph.hpp:191
class to create an executor
Definition executor.hpp:62
TaskGroup task_group()
creates a task group that executes a collection of asynchronous tasks
Definition task_group.hpp:863
Worker * this_worker()
queries pointer to the calling worker if it belongs to this executor, otherwise returns nullptr
class to create a task group from a task
Definition task_group.hpp:61
auto dependent_async(F &&func, Tasks &&... tasks)
runs the given function asynchronously when the given predecessors finish
Definition task_group.hpp:830
void corun()
corun all tasks spawned by this task group with other workers
Definition task_group.hpp:721
void cancel()
cancel all tasks in this task group
Definition task_group.hpp:732
size_t size() const
queries the number of tasks currently in this task group
Definition task_group.hpp:742
tf::AsyncTask silent_dependent_async(F &&func, Tasks &&... tasks)
runs the given function asynchronously when the given predecessors finish
Definition task_group.hpp:790
auto async(F &&f)
runs the given callable asynchronously
Definition task_group.hpp:771
TaskGroup & operator=(TaskGroup &&)=delete
disabled copy assignment
bool is_cancelled()
queries if the task group has been cancelled
Definition task_group.hpp:737
TaskGroup(TaskGroup &&)=delete
disabled move constructor
TaskGroup(const TaskGroup &)=delete
disabled copy constructor
Executor & executor()
obtains the executor that creates this task group
Definition task_group.hpp:716
void silent_async(F &&f)
runs the given function asynchronously without returning any future object
Definition task_group.hpp:752
class to create a worker in an executor
Definition worker.hpp:55
concept to check if a type is a tf::AsyncTask
Definition async_task.hpp:314
concept that determines if a type is a task parameter type
Definition graph.hpp:202
taskflow namespace
Definition small_vector.hpp:20