89 explicit task_group(Pool& pool) : pool_(pool), token_(
std::make_shared<context_token>()) {}
111 template <
typename F>
115 using function_type = std::decay_t<F>;
117 auto grouped = [token, function = function_type(std::forward<F>(f))]()
mutable
119 context_guard guard(current_group_, token.get());
120 std::invoke(std::move(function));
124 return run_inline(std::move(grouped));
125 return track(pool_.submit(std::move(grouped)));
132 context_guard(context_token*& slot, context_token* current) noexcept : slot_(slot), previous_(slot)
142 context_guard(context_guard
const&) =
delete;
143 auto operator=(context_guard
const&) -> context_guard& =
delete;
146 context_token*& slot_;
147 context_token* previous_;
150 template <
typename F>
152 run_inline(F&& function) -> result<void>
154 std::packaged_task<void()> task(std::forward<F>(function));
155 auto future = task.get_future();
157 return track(std::move(future));
161 track(std::future<void> future) -> result<void>
163 std::lock_guard<std::mutex> lock(mutex_);
164 futures_.push_back(std::move(future));
169 track(
result<std::future<void>> submitted) -> result<void>
172 return unexpected(submitted.error());
173 return track(std::move(*submitted));
189 if (current_group_ == token_.get())
190 throw_worker_wait_error();
192 std::exception_ptr first_error;
195 std::vector<std::future<void>> local;
197 std::lock_guard<std::mutex> lock(mutex_);
198 if (futures_.empty())
200 local.swap(futures_);
203 for (
auto& future : local)
212 first_error = std::current_exception();
218 std::rethrow_exception(first_error);
227 std::lock_guard<std::mutex> lock(mutex_);
228 return futures_.size();
232 [[noreturn]]
static void
233 throw_worker_wait_error()
235 throw std::system_error(std::make_error_code(std::errc::resource_deadlock_would_occur),
236 "task_group::wait from a tracked pool task");
239 inline static thread_local context_token* current_group_ =
nullptr;
241 std::shared_ptr<context_token> token_;
242 mutable std::mutex mutex_;
243 std::vector<std::future<void>> futures_;