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
103 Executor& executor();
104
105 // ----------------------------------------------------------------------------------------------
106 // async methods
107 // ----------------------------------------------------------------------------------------------
108
141 template <typename F>
142 auto async(F&& f);
143
165 template <typename 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
215 template <typename P, typename F>
216 void silent_async(P&& params, F&& f);
217
218 // ----------------------------------------------------------------------------------------------
219 // dependent async methods
220 // ----------------------------------------------------------------------------------------------
221
257 template <typename F, typename... Tasks>
258requires (std::same_as<std::decay_t<Tasks>, AsyncTask> && ...)
259 auto dependent_async(F&& func, Tasks&&... tasks);
260
300 template <TaskParameters P, typename F, typename... Tasks>
301 requires (std::same_as<std::decay_t<Tasks>, AsyncTask> && ...)
302 auto dependent_async(P&& params, F&& func, Tasks&&... tasks);
303
342 template <typename F, typename I>
343requires (!std::same_as<std::decay_t<I>, AsyncTask>)
344 auto dependent_async(F&& func, I first, I last);
345
388 template <TaskParameters P, typename F, typename I>
389 requires (!std::same_as<std::decay_t<I>, AsyncTask>)
390 auto dependent_async(P&& params, F&& func, I first, I last);
391
392
393 // ----------------------------------------------------------------------------------------------
394 // silent dependent async methods
395 // ----------------------------------------------------------------------------------------------
396
425 template <typename F, typename... Tasks>
426requires (std::same_as<std::decay_t<Tasks>, AsyncTask> && ...)
427 tf::AsyncTask silent_dependent_async(F&& func, Tasks&&... tasks);
428
461 template <TaskParameters P, typename F, typename... Tasks>
462 requires (std::same_as<std::decay_t<Tasks>, AsyncTask> && ...)
463 tf::AsyncTask silent_dependent_async(P&& params, F&& func, Tasks&&... tasks);
464
498 template <typename F, typename I>
499 requires (!std::same_as<std::decay_t<I>, AsyncTask>)
500 tf::AsyncTask silent_dependent_async(F&& func, I first, I last);
501
537 template <TaskParameters P, typename F, typename I>
538 requires (!std::same_as<std::decay_t<I>, AsyncTask>)
539 tf::AsyncTask silent_dependent_async(P&& params, F&& func, I first, I last);
540
541
542 // ----------------------------------------------------------------------------------------------
543 // cooperative execution methods
544 // ----------------------------------------------------------------------------------------------
545
578 void corun();
579
636 void cancel();
637
661 bool is_cancelled();
662
687 size_t size() const;
688
689 private:
690
694 explicit TaskGroup(Executor&, Worker&);
695
699 Executor& _executor;
700
704 Worker& _worker;
705
709 NodeBase _node_base;
710};
711
712// constructor
713inline TaskGroup::TaskGroup(Executor& executor, Worker& worker) :
714 _executor {executor},
715 _worker {worker},
716 _node_base {NSTATE::IMPLICITLY_ANCHORED, ESTATE::NONE, nullptr, 0} {
717}
718
719// Function: executor
720inline Executor& TaskGroup::executor() {
721 return _executor;
722}
723
724// Function: corun
725inline void TaskGroup::corun() {
726 {
727 ExplicitAnchorGuard anchor(&_node_base);
728 _executor._corun_until(_worker, [this] () -> bool {
729 return _node_base._join_counter.load(std::memory_order_acquire) == 0;
730 });
731 }
732 _node_base._rethrow_exception();
733}
734
735// Function: cancel
736inline void TaskGroup::cancel() {
737 _node_base._estate.fetch_or(ESTATE::CANCELLED, std::memory_order_relaxed);
738}
739
740// Function: is_cancelled
742 return _node_base._estate.load(std::memory_order_relaxed) & ESTATE::CANCELLED;
743}
744
745// Function: size
746inline size_t TaskGroup::size() const {
747 return _node_base._join_counter.load(std::memory_order_relaxed);
748}
749
750// ------------------------------------------------------------------------------------------------
751// TaskGroup::silent_async
752// ------------------------------------------------------------------------------------------------
753
754// Function: silent_async
755template <typename F>
757 silent_async(DefaultTaskParams{}, std::forward<F>(f));
758}
759
760// Function: silent_async
761template <typename P, typename F>
762void TaskGroup::silent_async(P&& params, F&& f) {
763 _node_base._join_counter.fetch_add(1, std::memory_order_relaxed);
764 _executor._silent_async(
765 std::forward<P>(params), std::forward<F>(f), nullptr, &_node_base
766 );
767}
768
769// ------------------------------------------------------------------------------------------------
770// TaskGroup::async
771// ------------------------------------------------------------------------------------------------
772
773// Function: async
774template <typename F>
775auto TaskGroup::async(F&& f) {
776 return async(DefaultTaskParams{}, std::forward<F>(f));
777}
778
779// Function: async
780template <typename P, typename F>
781auto TaskGroup::async(P&& params, F&& f) {
782 _node_base._join_counter.fetch_add(1, std::memory_order_relaxed);
783 return _executor._async(
784 std::forward<P>(params), std::forward<F>(f), nullptr, &_node_base
785 );
786}
787
788// ------------------------------------------------------------------------------------------------
789// silent dependent async
790// ------------------------------------------------------------------------------------------------
791
792// Function: silent_dependent_async
793template <typename F, typename... Tasks>
794requires (std::same_as<std::decay_t<Tasks>, AsyncTask> && ...)
797 DefaultTaskParams{}, std::forward<F>(func), std::forward<Tasks>(tasks)...
798 );
799}
800
801// Function: silent_dependent_async
802template <TaskParameters P, typename F, typename... Tasks>
803requires (std::same_as<std::decay_t<Tasks>, AsyncTask> && ...)
805 P&& params, F&& func, Tasks&&... tasks
806){
807 std::array<AsyncTask, sizeof...(Tasks)> array = { std::forward<Tasks>(tasks)... };
809 std::forward<P>(params), std::forward<F>(func), array.begin(), array.end()
810 );
811}
812
813// Function: silent_dependent_async
814template <typename F, typename I>
815requires (!std::same_as<std::decay_t<I>, AsyncTask>)
817 return silent_dependent_async(DefaultTaskParams{}, std::forward<F>(func), first, last);
818}
819
820// Function: silent_dependent_async
821template <TaskParameters P, typename F, typename I>
822requires (!std::same_as<std::decay_t<I>, AsyncTask>)
824 P&& params, F&& func, I first, I last
825) {
826 _node_base._join_counter.fetch_add(1, std::memory_order_relaxed);
827 return _executor._silent_dependent_async(
828 std::forward<P>(params), std::forward<F>(func), first, last, nullptr, &_node_base
829 );
830}
831
832// ------------------------------------------------------------------------------------------------
833// dependent async
834// ------------------------------------------------------------------------------------------------
835
836// Function: dependent_async
837template <typename F, typename... Tasks>
838requires (std::same_as<std::decay_t<Tasks>, AsyncTask> && ...)
839auto TaskGroup::dependent_async(F&& func, Tasks&&... tasks) {
840 return dependent_async(DefaultTaskParams{}, std::forward<F>(func), std::forward<Tasks>(tasks)...);
841}
842
843// Function: dependent_async
844template <TaskParameters P, typename F, typename... Tasks>
845requires (std::same_as<std::decay_t<Tasks>, AsyncTask> && ...)
846auto TaskGroup::dependent_async(P&& params, F&& func, Tasks&&... tasks) {
847 std::array<AsyncTask, sizeof...(Tasks)> array = { std::forward<Tasks>(tasks)... };
848 return dependent_async(
849 std::forward<P>(params), std::forward<F>(func), array.begin(), array.end()
850 );
851}
852
853// Function: dependent_async
854template <typename F, typename I>
855requires (!std::same_as<std::decay_t<I>, AsyncTask>)
856auto TaskGroup::dependent_async(F&& func, I first, I last) {
857 return dependent_async(DefaultTaskParams{}, std::forward<F>(func), first, last);
858}
859
860// Function: dependent_async
861template <TaskParameters P, typename F, typename I>
862requires (!std::same_as<std::decay_t<I>, AsyncTask>)
863auto TaskGroup::dependent_async(P&& params, F&& func, I first, I last) {
864 _node_base._join_counter.fetch_add(1, std::memory_order_relaxed);
865 return _executor._dependent_async(
866 std::forward<P>(params), std::forward<F>(func), first, last, nullptr, &_node_base
867 );
868}
869
870// ----------------------------------------------------------------------------
871// Executor Forward Declaration
872// ----------------------------------------------------------------------------
873
874// Procedure: task_group
875inline TaskGroup Executor::task_group() {
876 Worker* w = this_worker();
877 if(w == nullptr) {
878 TF_THROW("task_group can only created by a worker of the executor");
879 }
880 return TaskGroup(*this, *w);
881}
882
883
884} // 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:166
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:875
Worker * this_worker()
queries pointer to the calling worker if it belongs to this executor, otherwise returns nullptr
void corun()
corun all tasks spawned by this task group with other workers
Definition task_group.hpp:725
void cancel()
cancel all tasks in this task group
Definition task_group.hpp:736
size_t size() const
queries the number of tasks currently in this task group
Definition task_group.hpp:746
tf::AsyncTask silent_dependent_async(F &&func, Tasks &&... tasks)
runs the given function asynchronously when the given predecessors finish
Definition task_group.hpp:795
auto async(F &&f)
runs the given callable asynchronously
Definition task_group.hpp:775
TaskGroup & operator=(TaskGroup &&)=delete
disabled copy assignment
bool is_cancelled()
queries if the task group has been cancelled
Definition task_group.hpp:741
TaskGroup(TaskGroup &&)=delete
disabled move constructor
auto dependent_async(F &&func, Tasks &&... tasks)
runs the given function asynchronously when the given predecessors finish
Definition task_group.hpp:839
TaskGroup(const TaskGroup &)=delete
disabled copy constructor
Executor & executor()
obtains the executor that creates this task group
Definition task_group.hpp:720
void silent_async(F &&f)
runs the given function asynchronously without returning any future object
Definition task_group.hpp:756
class to create a worker in an executor
Definition worker.hpp:55
determines if a type is a task parameter type
Definition graph.hpp:177
taskflow namespace
Definition small_vector.hpp:20