userver: userver/engine/wait_all_checked.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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