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