Dispatch Queue
Dispatch Queue / Thread Pool implementation for C++11 with built-in C++20 coroutine support
 
Loading...
Searching...
No Matches
when_all.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <atomic>
4#include <exception>
5#include <memory>
6
7#include "detail/ranges.hpp"
8#include "task.hpp"
9
10namespace dispatch_queue {
11
12namespace detail {
13
15 when_all_helper(size_t count)
16 : result_count(std::make_shared<std::atomic<size_t>>(count))
17 {
18 }
19
20 template<typename T>
21 void operator()(const task<T>& task) const {
23 any_failed->store(true, std::memory_order_release);
24 }
25 if (result_count->fetch_sub(1, std::memory_order_acq_rel) == 1) {
26 if (any_failed->load(std::memory_order_acquire)) {
27 future->set_exception(std::make_exception_ptr(task_error("subtask failed")));
28 }
29 else {
30 future->set_value();
31 }
32 }
33 }
34
35 std::shared_ptr<std::atomic<size_t>> result_count;
36 std::shared_ptr<std::atomic<bool>> any_failed = std::make_shared<std::atomic<bool>>(false);
37 std::shared_ptr<detail::task_future<void>> future = detail::task_future<void>::create_pending();
38};
39
40template<typename TaskRange>
41task<void> when_all_internal(const TaskRange& tasks) {
42 auto tasks_size = detail::range_size(tasks);
43 if (tasks_size == 0) {
44 return detail::task_future<void>::create_ready();
45 }
46 else if (tasks_size == 1) {
47 return *detail::range_begin(tasks);
48 }
49
50 when_all_helper helper(tasks_size);
51 for (auto&& task : tasks) {
52 task.then(helper);
53 }
54 return helper.future;
55}
56
57} // end namespace detail
58
65template<typename T>
66task<void> when_all(std::initializer_list<task<T>> tasks) {
67 return detail::when_all_internal(tasks);
68}
69
76template<typename TaskRange>
77task<void> when_all(const TaskRange& tasks) {
78 return detail::when_all_internal(tasks);
79}
80
81#ifdef __cpp_fold_expressions
88 template<typename... Tasks>
89 task<void> when_all(const Tasks&... tasks) {
90 if constexpr (sizeof...(Tasks) == 0) {
91 return detail::task_future<void>::create_ready();
92 }
93 else if constexpr (sizeof...(Tasks) == 1) {
94 return std::get<0>(std::forward_as_tuple(std::forward<Tasks>(tasks)...));
95 }
96 else {
97 detail::when_all_helper helper(sizeof...(Tasks));
98 (tasks.then(helper), ...);
99 return helper.future;
100 }
101 }
102#endif // __cpp_fold_expressions
103
104} // end namespace dispatch_queue
Definition task_error.hpp:10
Definition task.hpp:32
task_state get_state() const
Definition task.hpp:193
auto then(F &&f) const
Definition task.hpp:124
Definition when_all.hpp:12
task< void > when_all_internal(const TaskRange &tasks)
Definition when_all.hpp:41
Definition dispatch_queue.hpp:19
task< void > when_all(std::initializer_list< task< T > > tasks)
Definition when_all.hpp:66
@ failed
Task failed with an exception.
Definition task_state.hpp:17
Definition when_all.hpp:14
void operator()(const task< T > &task) const
Definition when_all.hpp:21
std::shared_ptr< std::atomic< bool > > any_failed
Definition when_all.hpp:36
when_all_helper(size_t count)
Definition when_all.hpp:15
std::shared_ptr< std::atomic< size_t > > result_count
Definition when_all.hpp:35
std::shared_ptr< detail::task_future< void > > future
Definition when_all.hpp:37