ThreadSchedule 2.2.0
Modern C++ thread management library
Loading...
Searching...
No Matches
futures.hpp
Go to the documentation of this file.
1#pragma once
2
11
12#include "expected.hpp"
13
14#include <chrono>
15#include <exception>
16#include <future>
17#include <random>
18#include <stdexcept>
19#include <thread>
20#include <utility>
21#include <vector>
22
23namespace threadschedule
24{
25
36template <typename T>
37auto when_all(std::vector<std::future<T>>& futures) -> std::vector<T>
38{
39 std::vector<T> results;
40 results.reserve(futures.size());
41 std::exception_ptr first_error;
42
43 for (auto& f : futures)
44 {
45 try
46 {
47 results.push_back(f.get());
48 }
49 catch (...)
50 {
51 if (!first_error)
52 first_error = std::current_exception();
53 }
54 }
55
56 if (first_error)
57 std::rethrow_exception(first_error);
58
59 return results;
60}
61
67inline void when_all(std::vector<std::future<void>>& futures)
68{
69 std::exception_ptr first_error;
70
71 for (auto& f : futures)
72 {
73 try
74 {
75 f.get();
76 }
77 catch (...)
78 {
79 if (!first_error)
80 first_error = std::current_exception();
81 }
82 }
83
84 if (first_error)
85 std::rethrow_exception(first_error);
86}
87
96template <typename T>
97auto when_all_settled(std::vector<std::future<T>>& futures) -> std::vector<expected<T, std::exception_ptr>>
98{
99 std::vector<expected<T, std::exception_ptr>> results;
100 results.reserve(futures.size());
101
102 for (auto& f : futures)
103 {
104 try
105 {
106 results.push_back(f.get());
107 }
108 catch (...)
109 {
110 results.push_back(unexpected(std::current_exception()));
111 }
112 }
113
114 return results;
115}
116
120inline auto when_all_settled(std::vector<std::future<void>>& futures) -> std::vector<expected<void, std::exception_ptr>>
121{
122 std::vector<expected<void, std::exception_ptr>> results;
123 results.reserve(futures.size());
124
125 for (auto& f : futures)
126 {
127 try
128 {
129 f.get();
130 results.emplace_back();
131 }
132 catch (...)
133 {
134 results.push_back(unexpected(std::current_exception()));
135 }
136 }
137
138 return results;
139}
140
153template <typename T>
154auto when_any(std::vector<std::future<T>>& futures) -> std::pair<size_t, T>
155{
156 if (futures.empty())
157 throw std::invalid_argument("when_any: empty futures vector");
158
159 thread_local std::mt19937 rng{std::random_device{}()};
160 std::uniform_int_distribution<size_t> dist(0, futures.size() - 1);
161 size_t const start = dist(rng);
162 unsigned backoff_ms = 1;
163
164 while (true)
165 {
166 for (size_t k = 0; k < futures.size(); ++k)
167 {
168 size_t const i = (start + k) % futures.size();
169 if (futures[i].wait_for(std::chrono::milliseconds(1)) == std::future_status::ready)
170 return {i, futures[i].get()};
171 }
172 std::this_thread::sleep_for(std::chrono::milliseconds(backoff_ms));
173 if (backoff_ms < 16)
174 backoff_ms *= 2;
175 }
176}
177
184inline auto when_any(std::vector<std::future<void>>& futures) -> size_t
185{
186 if (futures.empty())
187 throw std::invalid_argument("when_any: empty futures vector");
188
189 thread_local std::mt19937 rng{std::random_device{}()};
190 std::uniform_int_distribution<size_t> dist(0, futures.size() - 1);
191 size_t const start = dist(rng);
192 unsigned backoff_ms = 1;
193
194 while (true)
195 {
196 for (size_t k = 0; k < futures.size(); ++k)
197 {
198 size_t const i = (start + k) % futures.size();
199 if (futures[i].wait_for(std::chrono::milliseconds(1)) == std::future_status::ready)
200 {
201 futures[i].get();
202 return i;
203 }
204 }
205 std::this_thread::sleep_for(std::chrono::milliseconds(backoff_ms));
206 if (backoff_ms < 16)
207 backoff_ms *= 2;
208 }
209}
210
211} // namespace threadschedule
Exception thrown by expected::value() when the object is in the error state.
Definition expected.hpp:162
Polyfill for std::expected (C++23) for pre-C++23 compilers.
auto when_all(std::vector< std::future< T > > &futures) -> std::vector< T >
Block until all futures complete, returning results in submission order.
Definition futures.hpp:37
auto when_all_settled(std::vector< std::future< T > > &futures) -> std::vector< expected< T, std::exception_ptr > >
Block until all futures complete, returning an expected per slot.
Definition futures.hpp:97
auto when_any(std::vector< std::future< T > > &futures) -> std::pair< size_t, T >
Block until the first future becomes ready.
Definition futures.hpp:154