userver: userver/engine/wait_all_checked.hpp Source File
Loading...
Searching...
No Matches
wait_all_checked.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/engine/wait_all_checked.hpp
4/// @brief Provides engine::WaitAllChecked
5
6#include <chrono>
7#include <vector>
8
9#include <userver/engine/deadline.hpp>
10#include <userver/engine/future_status.hpp>
11#include <userver/utils/meta.hpp>
12
13USERVER_NAMESPACE_BEGIN
14
15namespace engine {
16
17/// @ingroup userver_concurrency
18///
19/// @brief Waits for the successful completion of all of the specified tasks
20/// or for the cancellation of the caller.
21///
22/// Effectively performs `for (auto& task : tasks) task.Wait();` with a twist:
23/// if any task completes with an exception, it gets rethrown ASAP.
24///
25/// Invalid tasks are skipped.
26///
27/// Tasks are not invalidated by `WaitAllChecked`; the result can be retrieved
28/// after the call.
29///
30/// @param tasks either a single container, or a pack of future-like elements.
31/// @throws WaitInterruptedException when `current_task::ShouldCancel()` (for
32/// WaitAllChecked versions without a deadline)
33/// @throws std::exception one of specified tasks exception, if any, in no
34/// particular order.
35///
36/// @note Has overall computational complexity of O(N),
37/// where N is the number of tasks.
38/// @note Keeping the tasks valid may have a small extra memory impact. Make
39/// sure to drop the tasks after reading the results.
40/// @note Prefer engine::GetAll for tasks without a result, unless you
41/// specifically need to keep the tasks alive for some reason.
42template <typename... Tasks>
43void WaitAllChecked(Tasks&... tasks);
44
45/// @ingroup userver_concurrency
46///
47/// @overload void WaitAllChecked(Tasks&... tasks)
48template <typename... Tasks, typename Rep, typename Period>
49[[nodiscard]] FutureStatus WaitAllCheckedFor(const std::chrono::duration<Rep, Period>& duration, Tasks&... tasks);
50
51/// @ingroup userver_concurrency
52///
53/// @overload void WaitAllChecked(Tasks&... tasks)
54template <typename... Tasks, typename Clock, typename Duration>
55[[nodiscard]] FutureStatus WaitAllCheckedUntil(const std::chrono::time_point<Clock, Duration>& until, Tasks&... tasks);
56
57/// @ingroup userver_concurrency
58///
59/// @overload void WaitAllChecked(Tasks&... tasks)
60template <typename... Tasks>
61[[nodiscard]] FutureStatus WaitAllCheckedUntil(Deadline deadline, Tasks&... tasks);
62
63namespace impl {
64
65class ContextAccessor;
66
67FutureStatus DoWaitAllChecked(std::vector<ContextAccessor*>&& targets, Deadline deadline);
68
69template <typename Container>
70FutureStatus WaitAllCheckedFromContainer(Deadline deadline, Container& tasks) {
71 std::vector<ContextAccessor*> targets;
72 targets.reserve(std::size(tasks));
73
74 for (auto& task : tasks) {
75 targets.push_back(task.TryGetContextAccessor());
76 }
77
78 return impl::DoWaitAllChecked(std::move(targets), deadline);
79}
80
81template <typename... Tasks>
82FutureStatus WaitAllCheckedFromTasks(Deadline deadline, Tasks&... tasks) {
83 return impl::DoWaitAllChecked({tasks.TryGetContextAccessor()...}, deadline);
84}
85
86inline FutureStatus WaitAllCheckedFromTasks(Deadline /*deadline*/) { return FutureStatus::kReady; }
87
88void HandleWaitAllStatus(FutureStatus status);
89
90} // namespace impl
91
92template <typename... Tasks>
93void WaitAllChecked(Tasks&... tasks) {
94 impl::HandleWaitAllStatus(engine::WaitAllCheckedUntil(Deadline{}, tasks...));
95}
96
97template <typename... Tasks, typename Rep, typename Period>
98[[nodiscard]] FutureStatus WaitAllCheckedFor(const std::chrono::duration<Rep, Period>& duration, Tasks&... tasks) {
99 return WaitAllCheckedUntil(Deadline::FromDuration(duration), tasks...);
100}
101
102template <typename... Tasks, typename Clock, typename Duration>
103[[nodiscard]] FutureStatus WaitAllCheckedUntil(const std::chrono::time_point<Clock, Duration>& until, Tasks&... tasks) {
104 return WaitAllCheckedUntil(Deadline::FromTimePoint(until), tasks...);
105}
106
107template <typename... Tasks>
108[[nodiscard]] FutureStatus WaitAllCheckedUntil(Deadline deadline, Tasks&... tasks) {
109 if constexpr (meta::impl::IsSingleRange<Tasks...>()) {
110 return impl::WaitAllCheckedFromContainer(deadline, tasks...);
111 } else {
112 return impl::WaitAllCheckedFromTasks(deadline, tasks...);
113 }
114}
115
116} // namespace engine
117
118USERVER_NAMESPACE_END