| 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 <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>
258 requires (std::same_as<std::decay_t<Tasks>, AsyncTask> && ...)
259 auto dependent_async(F&& func, Tasks&&... tasks);
260
300 template <TaskParamsLike 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>
343 requires (!std::same_as<std::decay_t<I>, AsyncTask>)
344 auto dependent_async(F&& func, I first, I last);
345
388 template <TaskParamsLike 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>
426 requires (std::same_as<std::decay_t<Tasks>, AsyncTask> && ...)
427 tf::AsyncTask silent_dependent_async(F&& func, Tasks&&... tasks);
428
461 template <TaskParamsLike 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 <TaskParamsLike 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
713 inline 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
720 inline Executor& TaskGroup::executor() {
721 return _executor;
722}
723
724// Function: corun
725 inline 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
736 inline void TaskGroup::cancel() {
737 _node_base._estate.fetch_or(ESTATE::CANCELLED, std::memory_order_relaxed);
738}
739
740// Function: is_cancelled
741 inline bool TaskGroup::is_cancelled() {
742 return _node_base._estate.load(std::memory_order_relaxed) & ESTATE::CANCELLED;
743}
744
745// Function: size
746 inline 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
755 template <typename F>
756 void TaskGroup::silent_async(F&& f) {
757 silent_async(DefaultTaskParams{}, std::forward<F>(f));
758}
759
760// Function: silent_async
761 template <typename P, typename F>
762 void 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
774 template <typename F>
775 auto TaskGroup::async(F&& f) {
776 return async(DefaultTaskParams{}, std::forward<F>(f));
777}
778
779// Function: async
780 template <typename P, typename F>
781 auto 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
793 template <typename F, typename... Tasks>
794 requires (std::same_as<std::decay_t<Tasks>, AsyncTask> && ...)
795 tf::AsyncTask TaskGroup::silent_dependent_async(F&& func, Tasks&&... tasks) {
796 return silent_dependent_async(
797 DefaultTaskParams{}, std::forward<F>(func), std::forward<Tasks>(tasks)...
798 );
799}
800
801// Function: silent_dependent_async
802 template <TaskParamsLike P, typename F, typename... Tasks>
803 requires (std::same_as<std::decay_t<Tasks>, AsyncTask> && ...)
804 tf::AsyncTask TaskGroup::silent_dependent_async(
805 P&& params, F&& func, Tasks&&... tasks
806){
807 std::array<AsyncTask, sizeof...(Tasks)> array = { std::forward<Tasks>(tasks)... };
808 return silent_dependent_async(
809 std::forward<P>(params), std::forward<F>(func), array.begin(), array.end()
810 );
811}
812
813// Function: silent_dependent_async
814 template <typename F, typename I>
815 requires (!std::same_as<std::decay_t<I>, AsyncTask>)
816 tf::AsyncTask TaskGroup::silent_dependent_async(F&& func, I first, I last) {
817 return silent_dependent_async(DefaultTaskParams{}, std::forward<F>(func), first, last);
818}
819
820// Function: silent_dependent_async
821 template <TaskParamsLike P, typename F, typename I>
822 requires (!std::same_as<std::decay_t<I>, AsyncTask>)
823 tf::AsyncTask TaskGroup::silent_dependent_async(
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
837 template <typename F, typename... Tasks>
838 requires (std::same_as<std::decay_t<Tasks>, AsyncTask> && ...)
839 auto 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
844 template <TaskParamsLike P, typename F, typename... Tasks>
845 requires (std::same_as<std::decay_t<Tasks>, AsyncTask> && ...)
846 auto 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
854 template <typename F, typename I>
855 requires (!std::same_as<std::decay_t<I>, AsyncTask>)
856 auto 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
861 template <TaskParamsLike P, typename F, typename I>
862 requires (!std::same_as<std::decay_t<I>, AsyncTask>)
863 auto 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
875 inline 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 -----------------------------------------------------
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:875
tf::Executor::this_worker
Worker * this_worker()
queries pointer to the calling worker if it belongs to this executor, otherwise returns nullptr
tf::TaskGroup::corun
void corun()
corun all tasks spawned by this task group with other workers
Definition task_group.hpp:725
tf::TaskGroup::cancel
void cancel()
cancel all tasks in this task group
Definition task_group.hpp:736
tf::TaskGroup::size
size_t size() const
queries the number of tasks currently in this task group
Definition task_group.hpp:746
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:795
tf::TaskGroup::async
auto async(F &&f)
runs the given callable asynchronously
Definition task_group.hpp:775
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:741
tf::TaskGroup::TaskGroup
TaskGroup(TaskGroup &&)=delete
disabled move constructor
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:839
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:720
tf::TaskGroup::silent_async
void silent_async(F &&f)
runs the given function asynchronously without returning any future object
Definition task_group.hpp:756
tf::Worker
class to create a worker in an executor
Definition worker.hpp:55
tf::TaskParamsLike
determines if a type is a task parameter type
Definition graph.hpp:202
tf
taskflow namespace
Definition small_vector.hpp:20