|
|
| TaskGroup (const TaskGroup &)=delete |
| | disabled copy constructor
|
| |
|
| TaskGroup (TaskGroup &&)=delete |
| | disabled move constructor
|
| |
|
TaskGroup & | operator= (TaskGroup &&)=delete |
| | disabled copy assignment
|
| |
|
TaskGroup & | operator= (const TaskGroup &)=delete |
| | disabled move assignment
|
| |
| Executor & | executor () |
| | obtains the executor that creates this task group
|
| |
| template<typename F> |
| auto | async (F &&f) |
| | runs the given callable asynchronously
|
| |
| template<TaskParamsLike P, typename F> |
| auto | async (P &¶ms, F &&f) |
| | runs the given callable asynchronously
|
| |
| template<typename F> |
| void | silent_async (F &&f) |
| | runs the given function asynchronously without returning any future object
|
| |
| template<TaskParamsLike P, typename F> |
| void | silent_async (P &¶ms, F &&f) |
| | runs the given function asynchronously without returning any future object
|
| |
| template<typename F, AsyncTaskHandleLike... Tasks> |
| auto | dependent_async (F &&func, Tasks &&... tasks) |
| | runs the given function asynchronously when the given predecessors finish
|
| |
| template<TaskParamsLike P, typename F, AsyncTaskHandleLike... Tasks> |
| auto | dependent_async (P &¶ms, F &&func, Tasks &&... tasks) |
| | runs the given function asynchronously when the given predecessors finish
|
| |
| template<typename F, std::input_iterator I> |
| auto | dependent_async (F &&func, I first, I last) |
| | runs the given function asynchronously when the given range of predecessors finish
|
| |
| template<TaskParamsLike P, typename F, std::input_iterator I> |
| auto | dependent_async (P &¶ms, F &&func, I first, I last) |
| | runs the given function asynchronously when the given range of predecessors finish
|
| |
| template<typename F, AsyncTaskHandleLike... Tasks> |
| tf::AsyncTask | silent_dependent_async (F &&func, Tasks &&... tasks) |
| | runs the given function asynchronously when the given predecessors finish
|
| |
| template<TaskParamsLike P, typename F, AsyncTaskHandleLike... Tasks> |
| tf::AsyncTask | silent_dependent_async (P &¶ms, F &&func, Tasks &&... tasks) |
| | runs the given function asynchronously when the given predecessors finish
|
| |
| template<typename F, std::input_iterator I> |
| tf::AsyncTask | silent_dependent_async (F &&func, I first, I last) |
| | runs the given function asynchronously when the given range of predecessors finish
|
| |
| template<TaskParamsLike P, typename F, std::input_iterator I> |
| tf::AsyncTask | silent_dependent_async (P &¶ms, F &&func, I first, I last) |
| | runs the given function asynchronously when the given range of predecessors finish
|
| |
| void | corun () |
| | corun all tasks spawned by this task group with other workers
|
| |
| void | cancel () |
| | cancel all tasks in this task group
|
| |
| bool | is_cancelled () |
| | queries if the task group has been cancelled
|
| |
| size_t | size () const |
| | queries the number of tasks currently in this task group
|
| |
class to create a task group from a task
A task group executes a group of asynchronous tasks. It enables asynchronous task spawning, cooperative execution among worker threads, and naturally supports recursive parallelism. Due to cooperative execution, a task group can only be created by an executor worker; otherwise an exception will be thrown. The code below demonstrates how to use task groups to implement recursive Fibonacci parallelism.
size_t fibonacci(size_t N) {
if (N < 2) return N;
size_t res1, res2;
res2 = fibonacci(N-2);
return res1 + res2;
}
int main() {
size_t N = 30, res;
std::cout << N << "-th Fibonacci number is " << res << '\n';
return 0;
}
class to create an executor
Definition executor.hpp:62
auto async(P &¶ms, F &&func)
creates a parameterized asynchronous task to run the given function
class to create a task group from a task
Definition task_group.hpp:61
void corun()
corun all tasks spawned by this task group with other workers
Definition task_group.hpp:721
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
Users must explicitly call tf::TaskGroup::corun() to ensure that all tasks have completed or been properly canceled before leaving the scope of a task group. Failing to do so results in undefined behavior.
- Note
- To understand how Taskflow schedules a task group, please refer to Task Group.
| void tf::TaskGroup::cancel |
( |
| ) |
|
|
inline |
cancel all tasks in this task group
Marks the task group as cancelled to stop any not-yet-started tasks in the group from running. Tasks that are already running will continue to completion, but no new tasks belonging to the task group will be scheduled after cancellation.
This example below demonstrates how tf::TaskGroup::cancel() prevents pending tasks in a task group from executing, while allowing already running tasks to complete cooperatively. The first set of tasks deliberately occupies all but one worker thread, ensuring that subsequently spawned tasks remain pending. After invoking tf::TaskGroup::cancel(), these pending tasks are never scheduled, even after the blocked workers are released. A final call to tf::TaskGroup::corun() synchronizes with all tasks in the group, guaranteeing safe completion and verifying that cancellation successfully suppresses task execution.
const size_t W = 12;
std::atomic<size_t> latch(0);
for(size_t i=0; i<W-1; ++i) {
tg.async([&](){
++latch;
while(latch != 0);
});
}
while(latch != W-1);
for(size_t i=0; i<100; ++i) {
tg.async([&](){ throw std::runtime_error("this should never run"); });
}
assert(tg.is_cancelled() == false);
tg.cancel();
assert(tg.is_cancelled() == true);
latch = 0;
tg.corun();
});
Note that cancellation is cooperative: tasks should not assume immediate termination. Users must still call tf::TaskGroup::corun() to synchronize with all spawned tasks and ensure safe completion or cancellation. Failing to do so results in undefined behavior.
template<TaskParamsLike P, typename F, std::input_iterator I>
| auto tf::TaskGroup::dependent_async |
( |
P && | params, |
|
|
F && | func, |
|
|
I | first, |
|
|
I | last ) |
runs the given function asynchronously when the given range of predecessors finish
- Template Parameters
-
- Parameters
-
| params | task parameters |
| func | callable object |
| first | iterator to the beginning (inclusive) |
| last | iterator to the end (exclusive) |
- Returns
- a pair of a tf::AsyncTask handle and a std::future that holds the result of the execution
The example below creates three named asynchronous tasks, A, B, and C, in which task C runs after task A and task B. Task C returns a pair of its tf::AsyncTask handle and a std::future<int> that eventually will hold the result of the execution. Assigned task names will appear in the observers of the executor.
std::array<tf::AsyncTask, 2> array {
tg.silent_dependent_async("A", [](){ printf("A\n"); }),
tg.silent_dependent_async("B", [](){ printf("B\n"); })
};
auto [C, fuC] = tg.dependent_async(
"C",
[](){
printf("C runs after A and B\n");
return 1;
},
array.begin(), array.end()
);
fuC.get();
});