YACLib
C++ library for concurrent tasks execution
Loading...
Searching...
No Matches
wait_group.hpp
Go to the documentation of this file.
1#pragma once
2
6#include <yaclib/config.hpp>
9
10#include <cstddef>
11
12namespace yaclib {
13
14/**
15 * An object that allows you to Add some amount of async operations and then Wait for it to be Done
16 */
17template <typename Event = OneShotEvent>
19 public:
20 explicit WaitGroup(std::size_t count = 0) noexcept : _event{count} {
21 }
22
23 /**
24 * Add some amount of async operations
25 *
26 * Can be called parallel with Add, Done,
27 * and with Wait, but only if you call it when some Add not Done yet
28 *
29 * \param count of async operations
30 */
31 YACLIB_INLINE void Add(std::size_t count = 1) noexcept {
32 _event.Add(count);
33 }
34
35 /**
36 * Done some Add-ed async operations
37 *
38 * \param count of async operations
39 */
40 YACLIB_INLINE void Done(std::size_t count = 1) noexcept {
41 _event.Sub(count);
42 }
43
44 /**
45 * Consume \ref Future by WaitGroup with auto Done
46 *
47 * Also \see Add
48 *
49 * \tparam NeedAdd if true make implicit Add, if false you should make explicit Add before call Consume
50 * \param futures to wait
51 */
52 template <bool NeedAdd = true, typename... V, typename... E>
56
57 /**
58 * Consume \ref Future by WaitGroup with auto Done
59 *
60 * Also \see Add
61 *
62 * \tparam NeedAdd if true make implicit Add, if false you should make explicit Add before call Consume
63 * \param begin iterator to futures to Add
64 * \param end iterator to futures to Add
65 */
66 template <bool NeedAdd = true, typename It>
67 YACLIB_INLINE std::enable_if_t<!is_future_base_v<It>, void> Consume(It begin, It end) noexcept {
68 InsertIt<true, NeedAdd>(begin, static_cast<std::size_t>(end - begin));
69 }
70
71 /**
72 * Consume \ref Future by WaitGroup with auto Done
73 *
74 * Also \see Add
75 *
76 * \tparam NeedAdd if true make implicit Add, if false you should make explicit Add before call Consume
77 * \param begin iterator to futures to Add
78 * \param count count of futures to Add
79 */
80 template <bool NeedAdd = true, typename It>
81 YACLIB_INLINE void Consume(It begin, std::size_t count) noexcept {
83 }
84
85 /**
86 * Attach \ref Future to WaitGroup with auto Done
87 *
88 * Also \see Add
89 *
90 * \tparam NeedAdd if true make implicit Add, if false you should make explicit Add before call Attach
91 * \param futures to wait
92 */
93 template <bool NeedAdd = true, typename... V, typename... E>
97
98 /**
99 * Attach \ref Future to WaitGroup with auto Done
100 *
101 * Also \see Add
102 *
103 * \tparam NeedAdd if true make implicit Add, if false you should make explicit Add before call Attach
104 * \param begin iterator to futures to Add
105 * \param end iterator to futures to Add
106 */
107 template <bool NeedAdd = true, typename It>
108 YACLIB_INLINE std::enable_if_t<!is_future_base_v<It>, void> Attach(It begin, It end) noexcept {
109 InsertIt<false, NeedAdd>(begin, static_cast<std::size_t>(end - begin));
110 }
111
112 /**
113 * Attach \ref Future to WaitGroup with auto Done
114 *
115 * Also \see Add
116 *
117 * \tparam NeedAdd if true make implicit Add, if false you should make explicit Add before call Attach
118 * \param begin iterator to futures to Add
119 * \param count count of futures to Add
120 */
121 template <bool NeedAdd = true, typename It>
122 YACLIB_INLINE void Attach(It begin, std::size_t count) noexcept {
124 }
125
126 /**
127 * TODO
128 */
130 _event.Wait();
131 }
132 /**
133 * TODO
134 */
135 template <typename Rep, typename Period>
136 YACLIB_INLINE bool WaitFor(const std::chrono::duration<Rep, Period>& timeout_duration) {
137 return _event.WaitFor(timeout_duration);
138 }
139
140 /**
141 * TODO
142 */
143 template <typename Clock, typename Duration>
144 YACLIB_INLINE bool WaitUntil(const std::chrono::time_point<Clock, Duration>& timeout_time) {
145 return _event.WaitUntil(timeout_time);
146 }
147
148#if YACLIB_CORO != 0
149 /**
150 * See OneShotEvent::Await
151 */
153 return _event.Await();
154 }
155
156 /**
157 * See OneShotEvent::Await
158 */
160 return _event.AwaitSticky();
161 }
162
163 /**
164 * See OneShotEvent::AwaitOn
165 */
166 YACLIB_INLINE auto AwaitOn(IExecutor& e) noexcept {
167 return _event.AwaitOn(e);
168 }
169
170 /**
171 * just shortcut for co_await wait_group.Await();
172 *
173 * TODO(MBkkt) move all shortcut to AwaitSticky
174 */
175 YACLIB_INLINE auto operator co_await() noexcept {
176 return Await();
177 }
178#endif
179
180 /**
181 * Reinitializes WaitGroup, semantically the same as `*this = {};`
182 *
183 * If you don't explicitly call this method,
184 * then after the first one, Wait will always return immediately.
185 *
186 * \note Not thread-safe
187 */
188 YACLIB_INLINE void Reset(std::size_t count = 0) noexcept {
189 _event.Reset();
190 _event.count.store(count, std::memory_order_relaxed);
191 }
192
193 private:
194 template <bool NeedMove, bool NeedAdd, typename... Cores>
195 YACLIB_INLINE void InsertCore(Cores&... cores) noexcept {
196 static_assert(sizeof...(cores) >= 1, "Number of futures must be at least one");
197 static_assert((... && std::is_same_v<detail::BaseCore, Cores>),
198 "Futures must be Future in WaitGroup::Consume/Attach function");
199 auto range = [&](auto&& func) noexcept {
200 return (... + static_cast<std::size_t>(func(cores)));
201 };
203 }
204
205 template <bool NeedMove, bool NeedAdd, typename It>
206 YACLIB_INLINE void InsertIt(It it, std::size_t count) noexcept {
208 "WaitGroup::Consume/Attach function Iterator must be point to some Future");
209 if (count == 0) {
210 return;
211 }
212 auto range = [&](auto&& func) noexcept {
213 std::size_t wait_count = 0;
214 for (std::size_t i = 0; i != count; ++i) {
215 if constexpr (NeedMove) {
216 wait_count += static_cast<std::size_t>(func(*it->GetCore().Release()));
217 } else {
218 wait_count += static_cast<std::size_t>(func(*it->GetCore()));
219 }
220 ++it;
221 }
222 return wait_count;
223 };
225 }
226
227 template <bool NeedMove, bool NeedAdd, typename Range>
228 void InsertRange(const Range& range, std::size_t count) noexcept {
229 if constexpr (NeedAdd) {
230 Add(count);
231 }
232 const auto wait_count = range([&](detail::BaseCore& core) noexcept {
233 if constexpr (NeedMove) {
234 if (core.SetCallback(_event.GetDrop())) {
235 return true;
236 }
237 core.DecRef();
238 return false;
239 } else {
240 return core.SetCallback(_event.GetCall());
241 }
242 });
243 if (count != wait_count) { // TODO(MBkkt) is it necessary?
244 Done(count - wait_count);
245 }
246 }
247 detail::MultiEvent<Event, detail::AtomicCounter, detail::CallCallback, detail::DropCallback> _event;
248};
249
250extern template class WaitGroup<OneShotEvent>;
251
252} // namespace yaclib
Provides a mechanism to access the result of async operations.
Definition future.hpp:20
An object that allows you to Add some amount of async operations and then Wait for it to be Done.
YACLIB_INLINE void Reset(std::size_t count=0) noexcept
Reinitializes WaitGroup, semantically the same as *this = {};
YACLIB_INLINE void Wait() noexcept
TODO.
YACLIB_INLINE void Done(std::size_t count=1) noexcept
Done some Add-ed async operations.
YACLIB_INLINE void Add(std::size_t count=1) noexcept
Add some amount of async operations.
YACLIB_INLINE void Attach(FutureBase< V, E > &... futures) noexcept
Attach Future to WaitGroup with auto Done.
YACLIB_INLINE void Attach(It begin, std::size_t count) noexcept
Attach Future to WaitGroup with auto Done.
YACLIB_INLINE void Consume(FutureBase< V, E > &&... futures) noexcept
Consume Future by WaitGroup with auto Done.
YACLIB_INLINE std::enable_if_t<!is_future_base_v< It >, void > Consume(It begin, It end) noexcept
Consume Future by WaitGroup with auto Done.
YACLIB_INLINE bool WaitFor(const std::chrono::duration< Rep, Period > &timeout_duration)
TODO.
WaitGroup(std::size_t count=0) noexcept
YACLIB_INLINE void Consume(It begin, std::size_t count) noexcept
Consume Future by WaitGroup with auto Done.
YACLIB_INLINE bool WaitUntil(const std::chrono::time_point< Clock, Duration > &timeout_time)
TODO.
YACLIB_INLINE std::enable_if_t<!is_future_base_v< It >, void > Attach(It begin, It end) noexcept
Attach Future to WaitGroup with auto Done.
YACLIB_INLINE auto AwaitOn(IExecutor &e, FutureBase< V, E > &... fs) noexcept
Definition await_on.hpp:11
YACLIB_INLINE auto Await(Task< V, E > &task) noexcept
TODO(mkornaukhov03) Add doxygen docs.
Definition await.hpp:14
Contract< V, E > MakeContract()
Creates related future and promise.
Definition contract.hpp:25