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(const std::chrono::duration<Rep, Period>& duration, Tasks&... tasks);
51
52/// @ingroup userver_concurrency
53///
54/// @overload void WaitAllChecked(Tasks&... tasks)
55template <typename... Tasks, typename Clock, typename Duration>
56[[nodiscard]] FutureStatus WaitAllCheckedUntil(const std::chrono::time_point<Clock, Duration>& until, Tasks&... tasks);
57
58/// @ingroup userver_concurrency
59///
60/// @overload void WaitAllChecked(Tasks&... tasks)
61template <typename... Tasks>
62[[nodiscard]] FutureStatus WaitAllCheckedUntil(Deadline deadline, Tasks&... tasks);
63
64namespace impl {
65
66class ContextAccessor;
67
68FutureStatus DoWaitAllChecked(utils::span<ContextAccessor*> targets, Deadline deadline);
69
70template <typename Container>
71FutureStatus WaitAllCheckedFromContainer(Deadline deadline, Container& tasks) {
72 std::vector<ContextAccessor*> targets;
73 targets.reserve(std::size(tasks));
74
75 for (auto& task : tasks) {
76 targets.push_back(task.TryGetContextAccessor());
77 }
78
79 return impl::DoWaitAllChecked(targets, deadline);
80}
81
82template <typename... Tasks>
83FutureStatus WaitAllCheckedFromTasks(Deadline deadline, Tasks&... tasks) {
84 ContextAccessor* targets[]{tasks.TryGetContextAccessor()...};
85 return impl::DoWaitAllChecked(targets, deadline);
86}
87
88inline FutureStatus WaitAllCheckedFromTasks(Deadline /*deadline*/) { return FutureStatus::kReady; }
89
90void HandleWaitAllStatus(FutureStatus status);
91
92} // namespace impl
93
94template <typename... Tasks>
95void WaitAllChecked(Tasks&... tasks) {
96 impl::HandleWaitAllStatus(engine::WaitAllCheckedUntil(Deadline{}, tasks...));
97}
98
99template <typename... Tasks, typename Rep, typename Period>
100[[nodiscard]] FutureStatus WaitAllCheckedFor(const std::chrono::duration<Rep, Period>& duration, Tasks&... tasks) {
101 return WaitAllCheckedUntil(Deadline::FromDuration(duration), tasks...);
102}
103
104template <typename... Tasks, typename Clock, typename Duration>
105[[nodiscard]] FutureStatus WaitAllCheckedUntil(const std::chrono::time_point<Clock, Duration>& until, Tasks&... tasks) {
106 return WaitAllCheckedUntil(Deadline::FromTimePoint(until), tasks...);
107}
108
109template <typename... Tasks>
110[[nodiscard]] FutureStatus WaitAllCheckedUntil(Deadline deadline, Tasks&... tasks) {
111 if constexpr (meta::impl::IsSingleRange<Tasks...>()) {
112 return impl::WaitAllCheckedFromContainer(deadline, tasks...);
113 } else {
114 return impl::WaitAllCheckedFromTasks(deadline, tasks...);
115 }
116}
117
118} // namespace engine
119
120USERVER_NAMESPACE_END