threadman 0.1.0
Header-only C++23 managed threads, dynamic pools, futures, and executors
Loading...
Searching...
No Matches
future.hpp
Go to the documentation of this file.
1#pragma once
2
26
28#include <threadman/log.hpp>
29#include <threadman/metrics.hpp>
30#include <threadman/stats.hpp>
31
32#include <commons/display_info.hpp>
33
34#include <atomic>
35#include <chrono>
36#include <condition_variable>
37#include <cstddef>
38#include <cstdint>
39#include <exception>
40#include <functional>
41#include <memory>
42#include <mutex>
43#include <optional>
44#include <type_traits>
45#include <utility>
46#include <vector>
47
48namespace threadman {
49
50class IExecutor; // forward — defined in <threadman/executor.hpp>
51
52namespace detail {
53
54template <class T>
55struct FutureSlot {
56 std::optional<T> value;
57};
58
59template <>
60struct FutureSlot<void> {};
61
62template <class T>
63class FutureState : public std::enable_shared_from_this<FutureState<T>> {
64public:
65 using value_type = T;
66 using Continuation = std::function<void()>;
67
68 bool ready() const noexcept {
69 return ready_.load(std::memory_order_acquire);
70 }
71 bool has_exception() const noexcept {
72 return exception_set_.load(std::memory_order_acquire);
73 }
74 std::uint32_t continuation_count() const noexcept {
75 std::scoped_lock guard(mtx_);
76 return static_cast<std::uint32_t>(continuations_.size());
77 }
78
79 FutureSnapshot snapshot(const bool shared) const {
80 FutureSnapshot snap;
81 snap.ready = ready();
84 snap.shared = shared;
85 return snap;
86 }
87
88 template <class U = T>
89 requires(!std::is_void_v<U>)
90 void set_value(U&& v) {
91 std::vector<Continuation> to_run;
92 {
93 std::unique_lock lock(mtx_);
94 if (ready_.load(std::memory_order_relaxed)) {
95 throw PromiseAlreadySatisfiedError("promise already satisfied");
96 }
97 slot_.value.emplace(std::forward<U>(v));
98 ready_.store(true, std::memory_order_release);
99 to_run.swap(continuations_);
100 cv_.notify_all();
101 }
103 for (auto& c : to_run) {
104 c();
105 }
106 }
107
108 template <class U = T>
109 requires std::is_void_v<U>
110 void set_value() {
111 std::vector<Continuation> to_run;
112 {
113 std::unique_lock lock(mtx_);
114 if (ready_.load(std::memory_order_relaxed)) {
115 throw PromiseAlreadySatisfiedError("promise already satisfied");
116 }
117 ready_.store(true, std::memory_order_release);
118 to_run.swap(continuations_);
119 cv_.notify_all();
120 }
122 for (auto& c : to_run) {
123 c();
124 }
125 }
126
127 void set_exception(const std::exception_ptr& ex) {
128 std::vector<Continuation> to_run;
129 {
130 std::unique_lock lock(mtx_);
131 if (ready_.load(std::memory_order_relaxed)) {
132 throw PromiseAlreadySatisfiedError("promise already satisfied");
133 }
134 exception_ = ex;
135 exception_set_.store(true, std::memory_order_release);
136 ready_.store(true, std::memory_order_release);
137 to_run.swap(continuations_);
138 cv_.notify_all();
139 }
141 for (auto& c : to_run) {
142 c();
143 }
144 }
145
146 void wait() const {
147 std::unique_lock lock(mtx_);
148 cv_.wait(lock, [this] { return ready_.load(std::memory_order_acquire); });
149 }
150
151 template <class Rep, class Period>
152 bool wait_for(const std::chrono::duration<Rep, Period>& dur) const {
153 std::unique_lock lock(mtx_);
154 return cv_.wait_for(lock, dur, [this] { return ready_.load(std::memory_order_acquire); });
155 }
156
157 template <class Clock, class Duration>
158 bool wait_until(const std::chrono::time_point<Clock, Duration>& tp) const {
159 std::unique_lock lock(mtx_);
160 return cv_.wait_until(lock, tp, [this] { return ready_.load(std::memory_order_acquire); });
161 }
162
165 template <class U = T>
166 requires(!std::is_void_v<U>)
168 wait();
169 if (has_exception()) {
170 std::rethrow_exception(exception_);
171 }
172 return std::move(*slot_.value);
173 }
174
175 template <class U = T>
176 requires(!std::is_void_v<U>)
177 const U& get_value_ref() const {
178 wait();
179 if (has_exception()) {
180 std::rethrow_exception(exception_);
181 }
182 return *slot_.value;
183 }
184
185 template <class U = T>
186 requires std::is_void_v<U>
187 void get_value_void() const {
188 wait();
189 if (has_exception()) {
190 std::rethrow_exception(exception_);
191 }
192 }
193
198
200 std::unique_lock lock(mtx_);
201 if (ready_.load(std::memory_order_relaxed)) {
203 }
204 continuations_.push_back(std::move(cb));
206 }
207
208 std::exception_ptr exception() const noexcept {
209 return exception_;
210 }
211
212private:
213 mutable std::mutex mtx_;
214 mutable std::condition_variable cv_;
215 std::atomic<bool> ready_{false};
216 std::atomic<bool> exception_set_{false};
217 FutureSlot<T> slot_;
218 std::exception_ptr exception_;
219 std::vector<Continuation> continuations_;
220};
221
222// Forward reference to the dispatch helper defined in the higher-tier
223// <threadman/executor.hpp>; future.hpp must not include executor.hpp (it sits
224// below it in the dependency order), so the declaration is intentional.
225// NOLINTNEXTLINE(readability-redundant-declaration)
226void execute_on(IExecutor& exec, std::function<void()> task);
227
228} // namespace detail
229
230template <class T>
231class Promise;
232template <class T>
233class SharedFuture;
234
235// ---------------------------------------------------------------------------
236// Future<T> — one-shot, move-only.
237// ---------------------------------------------------------------------------
238template <class T>
239class Future {
240public:
241 using value_type = T;
242
243 Future() = default;
244 Future(const Future&) = delete;
245 Future& operator=(const Future&) = delete;
246 Future(Future&&) noexcept = default;
247 Future& operator=(Future&&) noexcept = default;
248 ~Future() = default;
249
250 [[nodiscard]] bool valid() const noexcept {
251 return static_cast<bool>(state_);
252 }
253 [[nodiscard]] bool is_ready() const noexcept {
254 return state_ && state_->ready();
255 }
256
257 void wait() const {
258 check_valid();
259 state_->wait();
260 }
261
262 template <class Rep, class Period>
263 [[nodiscard]] bool wait_for(const std::chrono::duration<Rep, Period>& dur) const {
264 check_valid();
265 return state_->wait_for(dur);
266 }
267
268 template <class Clock, class Duration>
269 [[nodiscard]] bool wait_until(const std::chrono::time_point<Clock, Duration>& tp) const {
270 check_valid();
271 return state_->wait_until(tp);
272 }
273
275 template <class U = T>
276 requires(!std::is_void_v<U>)
277 U get() {
278 check_valid();
279 auto s = std::move(state_);
280 return s->get_value_move();
281 }
282
283 template <class U = T>
284 requires std::is_void_v<U>
285 void get() {
286 check_valid();
287 auto s = std::move(state_);
288 s->get_value_void();
289 }
290
292 [[nodiscard]] SharedFuture<T> share();
293
296 template <class Exec, class Fn>
297 auto then(Exec& exec, Fn&& fn);
298
302 template <class Exec, class Fn>
303 Future<T> on_error(Exec& exec, Fn&& fn);
304
305 [[nodiscard]] FutureSnapshot snapshot() const {
306 return state_ ? state_->snapshot(false) : FutureSnapshot{};
307 }
308
309 [[nodiscard]] static const comms::DisplayInfo& display_info() {
310 static const comms::DisplayInfo info{
311 .name = "Future",
312 .description = "One-shot, move-only async result with single .get and single .then.",
313 .icon = comms::Icon::from("mdi:clock-fast"),
314 };
315 return info;
316 }
317
318private:
319 template <class U>
320 friend class Promise;
321 template <class U>
322 friend class SharedFuture;
323 template <class U>
324 friend class Future;
325
326 explicit Future(std::shared_ptr<detail::FutureState<T>> s) : state_(std::move(s)) {}
327
328 void check_valid() const {
329 if (!state_) {
330 throw FutureError("future has no state (default-constructed or moved-from)");
331 }
332 }
333
334 std::shared_ptr<detail::FutureState<T>> state_;
335 bool has_continuation_{false};
336};
337
338// ---------------------------------------------------------------------------
339// SharedFuture<T> — multi-shot, copyable.
340// ---------------------------------------------------------------------------
341template <class T>
343public:
344 using value_type = T;
345
346 SharedFuture() = default;
347 SharedFuture(const SharedFuture&) = default;
348 SharedFuture(SharedFuture&&) noexcept = default;
349 SharedFuture& operator=(const SharedFuture&) = default;
350 SharedFuture& operator=(SharedFuture&&) noexcept = default;
351 ~SharedFuture() = default;
352
353 [[nodiscard]] bool valid() const noexcept {
354 return static_cast<bool>(state_);
355 }
356 [[nodiscard]] bool is_ready() const noexcept {
357 return state_ && state_->ready();
358 }
359
360 void wait() const {
361 check_valid();
362 state_->wait();
363 }
364
365 template <class Rep, class Period>
366 [[nodiscard]] bool wait_for(const std::chrono::duration<Rep, Period>& dur) const {
367 check_valid();
368 return state_->wait_for(dur);
369 }
370
374 template <class U = T>
375 requires(!std::is_void_v<U>)
376 const U& get() const {
377 check_valid();
378 return state_->get_value_ref();
379 }
380
381 template <class U = T>
382 requires std::is_void_v<U>
383 void get() const {
384 check_valid();
385 state_->get_value_void();
386 }
387
388 template <class Exec, class Fn>
389 auto then(Exec& exec, Fn&& fn) const;
390
391 template <class Exec, class Fn>
392 SharedFuture<T> on_error(Exec& exec, Fn&& fn) const;
393
394 [[nodiscard]] FutureSnapshot snapshot() const {
395 return state_ ? state_->snapshot(true) : FutureSnapshot{};
396 }
397
398 [[nodiscard]] static const comms::DisplayInfo& display_info() {
399 static const comms::DisplayInfo info{
400 .name = "SharedFuture",
401 .description = "Multi-shot, copyable async result supporting many .get and .then.",
402 .icon = comms::Icon::from("mdi:clock-multiple"),
403 };
404 return info;
405 }
406
407private:
408 template <class U>
409 friend class Future;
410 template <class U>
411 friend class SharedFuture;
412 template <class U>
413 friend class Promise;
414
415 explicit SharedFuture(std::shared_ptr<detail::FutureState<T>> s) : state_(std::move(s)) {}
416
417 void check_valid() const {
418 if (!state_) {
419 throw FutureError("shared_future has no state (default-constructed)");
420 }
421 }
422
423 std::shared_ptr<detail::FutureState<T>> state_;
424};
425
426template <class T>
428 check_valid();
429 return SharedFuture<T>{std::move(state_)};
430}
431
432// ---------------------------------------------------------------------------
433// Promise<T>.
434// ---------------------------------------------------------------------------
435template <class T>
436class Promise {
437public:
438 using value_type = T;
439
440 Promise() : state_(std::make_shared<detail::FutureState<T>>()) {
442 }
443 Promise(const Promise&) = delete;
444 Promise& operator=(const Promise&) = delete;
445 Promise(Promise&&) noexcept = default;
446 Promise& operator=(Promise&&) noexcept = default;
447
449 if (state_ && !state_->ready()) {
450 try {
451 state_->set_exception(std::make_exception_ptr(
452 BrokenPromiseError("promise destroyed before satisfaction")));
453 } catch (...) {
454 // dtor must not propagate
455 }
456 }
457 }
458
459 [[nodiscard]] bool valid() const noexcept {
460 return static_cast<bool>(state_);
461 }
462
465 [[nodiscard]] Future<T> get_future() {
466 if (!state_) {
467 throw FutureError("promise has no state");
468 }
469 if (future_retrieved_) {
470 throw FutureAlreadyRetrievedError("future already retrieved from promise");
471 }
472 future_retrieved_ = true;
473 return Future<T>{state_};
474 }
475
476 template <class U = T>
477 requires(!std::is_void_v<U>)
478 void set_value(U&& v) {
479 if (!state_) {
480 throw FutureError("promise has no state");
481 }
482 state_->set_value(std::forward<U>(v));
483 }
484
485 template <class U = T>
486 requires std::is_void_v<U>
487 void set_value() {
488 if (!state_) {
489 throw FutureError("promise has no state");
490 }
491 state_->set_value();
492 }
493
494 void set_exception(const std::exception_ptr& ex) {
495 if (!state_) {
496 throw FutureError("promise has no state");
497 }
498 state_->set_exception(ex);
499 }
500
501 [[nodiscard]] static const comms::DisplayInfo& display_info() {
502 static const comms::DisplayInfo info{
503 .name = "Promise",
504 .description = "Producer side of a Future/SharedFuture pair.",
505 .icon = comms::Icon::from("mdi:handshake"),
506 };
507 return info;
508 }
509
510private:
511 std::shared_ptr<detail::FutureState<T>> state_;
512 bool future_retrieved_ = false;
513};
514
515// ---------------------------------------------------------------------------
516// .then() implementations
517// ---------------------------------------------------------------------------
518namespace detail {
519
520template <class Fn, class Arg>
521struct invoke_result_helper {
522 using type = std::invoke_result_t<Fn, Arg>;
523};
524
525template <class Fn>
526struct invoke_result_helper<Fn, void> {
527 using type = std::invoke_result_t<Fn>;
528};
529
530template <class Fn, class Arg>
531using future_invoke_result_t = typename invoke_result_helper<Fn, Arg>::type;
532
533template <class T, class Fn, class Sink>
534inline void run_continuation(const std::shared_ptr<FutureState<T>>& src,
535 Fn& fn,
536 const std::shared_ptr<Sink>& sink_promise) {
538 using SinkT = typename Sink::value_type;
539 try {
540 if (src->has_exception()) {
541 sink_promise->set_exception(src->exception());
542 return;
543 }
544 if constexpr (std::is_void_v<T>) {
545 if constexpr (std::is_void_v<SinkT>) {
546 fn();
547 sink_promise->set_value();
548 } else {
549 sink_promise->set_value(fn());
550 }
551 } else {
552 if constexpr (std::is_void_v<SinkT>) {
553 fn(src->get_value_ref());
554 sink_promise->set_value();
555 } else {
556 sink_promise->set_value(fn(src->get_value_ref()));
557 }
558 }
559 } catch (...) {
560 sink_promise->set_exception(std::current_exception());
561 }
562}
563
564} // namespace detail
565
566template <class T>
567template <class Exec, class Fn>
568auto Future<T>::then(Exec& exec, Fn&& fn) {
569 check_valid();
570 if (has_continuation_) {
572 "Future::then already registered; use share() for multi-shot");
573 }
574 has_continuation_ = true;
576 using U = typename detail::invoke_result_helper<std::decay_t<Fn>, T>::type;
577
578 auto sink_promise = std::make_shared<Promise<U>>();
579 auto sink_future = sink_promise->get_future();
580
581 auto src = state_; // keep state_ alive on this Future too — only the
582 // has_continuation_ flag prevents reuse, so that a
583 // second .then() throws ContinuationAlreadyRegisteredError
584 // rather than the generic "no state" FutureError.
585 auto fn_shared = std::make_shared<std::decay_t<Fn>>(std::forward<Fn>(fn));
586
587 auto schedule = [&exec, src, fn_shared, sink_promise]() {
588 detail::execute_on(exec, [src, fn_shared, sink_promise]() {
589 detail::run_continuation<T>(src, *fn_shared, sink_promise);
590 });
591 };
592
593 auto result = src->add_continuation([schedule = std::move(schedule)]() mutable { schedule(); });
595 detail::execute_on(exec, [src, fn_shared, sink_promise]() {
596 detail::run_continuation<T>(src, *fn_shared, sink_promise);
597 });
598 }
599 return sink_future;
600}
601
602template <class T>
603template <class Exec, class Fn>
604Future<T> Future<T>::on_error(Exec& exec, Fn&& fn) {
605 check_valid();
606 if (has_continuation_) {
608 "Future::on_error already registered (a Future supports a single continuation)");
609 }
610 has_continuation_ = true;
612 auto sink_promise = std::make_shared<Promise<T>>();
613 auto sink_future = sink_promise->get_future();
614
615 auto src = state_;
616 auto fn_shared = std::make_shared<std::decay_t<Fn>>(std::forward<Fn>(fn));
617
618 auto run = [src, fn_shared, sink_promise]() {
620 try {
621 if (src->has_exception()) {
622 if constexpr (std::is_void_v<T>) {
623 (*fn_shared)(src->exception());
624 sink_promise->set_value();
625 } else {
626 auto recovered = (*fn_shared)(src->exception());
627 sink_promise->set_value(std::move(recovered));
628 }
629 } else {
630 if constexpr (std::is_void_v<T>) {
631 sink_promise->set_value();
632 } else {
633 sink_promise->set_value(T{src->get_value_ref()});
634 }
635 }
636 } catch (...) {
637 sink_promise->set_exception(std::current_exception());
638 }
639 };
640
641 auto schedule = [&exec, run = std::move(run)]() mutable { detail::execute_on(exec, run); };
642
643 auto result = src->add_continuation([schedule = std::move(schedule)]() mutable { schedule(); });
645 detail::execute_on(exec, [src, fn_shared, sink_promise]() {
646 try {
647 if (src->has_exception()) {
648 if constexpr (std::is_void_v<T>) {
649 (*fn_shared)(src->exception());
650 sink_promise->set_value();
651 } else {
652 auto recovered = (*fn_shared)(src->exception());
653 sink_promise->set_value(std::move(recovered));
654 }
655 } else {
656 if constexpr (std::is_void_v<T>) {
657 sink_promise->set_value();
658 } else {
659 sink_promise->set_value(T{src->get_value_ref()});
660 }
661 }
662 } catch (...) {
663 sink_promise->set_exception(std::current_exception());
664 }
665 });
666 }
667 return sink_future;
668}
669
670template <class T>
671template <class Exec, class Fn>
672auto SharedFuture<T>::then(Exec& exec, Fn&& fn) const {
673 check_valid();
674 metrics::future_continuations_registered().inc();
675 using U = typename detail::invoke_result_helper<std::decay_t<Fn>, T>::type;
676
677 auto sink_promise = std::make_shared<Promise<U>>();
678 auto sink_future = sink_promise->get_future();
679
680 auto src = state_;
681 auto fn_shared = std::make_shared<std::decay_t<Fn>>(std::forward<Fn>(fn));
682
683 auto schedule = [&exec, src, fn_shared, sink_promise]() {
684 detail::execute_on(exec, [src, fn_shared, sink_promise]() {
685 detail::run_continuation<T>(src, *fn_shared, sink_promise);
686 });
687 };
688
689 auto result = src->add_continuation([schedule = std::move(schedule)]() mutable { schedule(); });
691 detail::execute_on(exec, [src, fn_shared, sink_promise]() {
692 detail::run_continuation<T>(src, *fn_shared, sink_promise);
693 });
694 }
695 return sink_future;
696}
697
698template <class T>
699template <class Exec, class Fn>
700SharedFuture<T> SharedFuture<T>::on_error(Exec& exec, Fn&& fn) const {
701 check_valid();
702 metrics::future_continuations_registered().inc();
703 auto sink_promise = std::make_shared<Promise<T>>();
704 auto sink_future = sink_promise->get_future().share();
705
706 auto src = state_;
707 auto fn_shared = std::make_shared<std::decay_t<Fn>>(std::forward<Fn>(fn));
708
709 auto run = [src, fn_shared, sink_promise]() {
710 metrics::future_continuations_dispatched().inc();
711 try {
712 if (src->has_exception()) {
713 if constexpr (std::is_void_v<T>) {
714 (*fn_shared)(src->exception());
715 sink_promise->set_value();
716 } else {
717 auto recovered = (*fn_shared)(src->exception());
718 sink_promise->set_value(std::move(recovered));
719 }
720 } else {
721 if constexpr (std::is_void_v<T>) {
722 sink_promise->set_value();
723 } else {
724 sink_promise->set_value(T{src->get_value_ref()});
725 }
726 }
727 } catch (...) {
728 sink_promise->set_exception(std::current_exception());
729 }
730 };
731
732 auto schedule = [&exec, run = std::move(run)]() mutable { detail::execute_on(exec, run); };
733
734 auto result = src->add_continuation([schedule = std::move(schedule)]() mutable { schedule(); });
736 detail::execute_on(exec, run);
737 }
738 return sink_future;
739}
740
741} // namespace threadman
A Promise was dropped before it satisfied its Future.
Definition exceptions.hpp:39
A second .then() was registered on a one-shot threadman::Future.
Definition exceptions.hpp:59
Promise::get_future() was called more than once on the same promise.
Definition exceptions.hpp:45
Generic future/promise error.
Definition exceptions.hpp:32
Definition future.hpp:239
Future(Future &&) noexcept=default
auto then(Exec &exec, Fn &&fn)
Register a continuation; consumes this future.
Definition future.hpp:568
Future< T > on_error(Exec &exec, Fn &&fn)
Recover from a captured exception by running fn(exception_ptr).
Definition future.hpp:604
FutureSnapshot snapshot() const
Definition future.hpp:305
void wait() const
Definition future.hpp:257
Future(const Future &)=delete
bool wait_for(const std::chrono::duration< Rep, Period > &dur) const
Definition future.hpp:263
friend class Future
Definition future.hpp:324
Future & operator=(const Future &)=delete
bool is_ready() const noexcept
Definition future.hpp:253
bool wait_until(const std::chrono::time_point< Clock, Duration > &tp) const
Definition future.hpp:269
SharedFuture< T > share()
Convert to a multi-shot SharedFuture. Future is invalidated.
Definition future.hpp:427
bool valid() const noexcept
Definition future.hpp:250
static const comms::DisplayInfo & display_info()
Definition future.hpp:309
void get()
Definition future.hpp:285
U get()
Block, then consume — second get() throws.
Definition future.hpp:277
T value_type
Definition future.hpp:241
set_value() / set_exception() was called twice on the same promise.
Definition exceptions.hpp:51
Definition future.hpp:436
Promise()
Definition future.hpp:440
T value_type
Definition future.hpp:438
void set_value(U &&v)
Definition future.hpp:478
Future< T > get_future()
Retrieve the future.
Definition future.hpp:465
void set_value()
Definition future.hpp:487
Promise & operator=(const Promise &)=delete
Promise(const Promise &)=delete
void set_exception(const std::exception_ptr &ex)
Definition future.hpp:494
Promise(Promise &&) noexcept=default
static const comms::DisplayInfo & display_info()
Definition future.hpp:501
bool valid() const noexcept
Definition future.hpp:459
Definition future.hpp:342
FutureSnapshot snapshot() const
Definition future.hpp:394
T value_type
Definition future.hpp:344
SharedFuture(const SharedFuture &)=default
bool is_ready() const noexcept
Definition future.hpp:356
void wait() const
Definition future.hpp:360
SharedFuture< T > on_error(Exec &exec, Fn &&fn) const
Definition future.hpp:700
SharedFuture(SharedFuture &&) noexcept=default
bool valid() const noexcept
Definition future.hpp:353
static const comms::DisplayInfo & display_info()
Definition future.hpp:398
const U & get() const
Non-consuming read.
Definition future.hpp:376
auto then(Exec &exec, Fn &&fn) const
Definition future.hpp:672
friend class SharedFuture
Definition future.hpp:411
void get() const
Definition future.hpp:383
bool wait_for(const std::chrono::duration< Rep, Period > &dur) const
Definition future.hpp:366
Definition future.hpp:63
T value_type
Definition future.hpp:65
std::function< void()> Continuation
Definition future.hpp:66
U get_value_move()
Block until ready, then either return the value (move/copy depending on T) or rethrow the captured ex...
Definition future.hpp:167
void set_value(U &&v)
Definition future.hpp:90
bool has_exception() const noexcept
Definition future.hpp:71
void set_exception(const std::exception_ptr &ex)
Definition future.hpp:127
AddResult add_continuation(Continuation cb)
Definition future.hpp:199
std::exception_ptr exception() const noexcept
Definition future.hpp:208
void wait() const
Definition future.hpp:146
FutureSnapshot snapshot(const bool shared) const
Definition future.hpp:79
void set_value()
Definition future.hpp:110
bool wait_for(const std::chrono::duration< Rep, Period > &dur) const
Definition future.hpp:152
bool ready() const noexcept
Definition future.hpp:68
std::uint32_t continuation_count() const noexcept
Definition future.hpp:74
AddResult
Register a continuation.
Definition future.hpp:197
void get_value_void() const
Definition future.hpp:187
const U & get_value_ref() const
Definition future.hpp:177
bool wait_until(const std::chrono::time_point< Clock, Duration > &tp) const
Definition future.hpp:158
Typed exception hierarchy thrown by ThreadMan.
Cached subsystem loggers for the tm.
Cached subsystem metrics for the tm_* Prometheus/OpenMetrics families, mirroring the tm.
void execute_on(IExecutor &exec, std::function< void()> task)
Dispatch helper used by Future::then / SharedFuture::then.
Definition executor.hpp:48
prom::Counter & future_continuations_registered()
.then/.on_error continuations registered against a future.
Definition metrics.hpp:252
prom::Counter & futures_satisfied_value()
Futures satisfied with a value.
Definition metrics.hpp:238
prom::Counter & future_continuations_dispatched()
Continuations dispatched through an executor.
Definition metrics.hpp:260
prom::Counter & futures_satisfied_exception()
Futures satisfied with an exception.
Definition metrics.hpp:245
prom::Counter & futures_created()
Promise/Future pairs created.
Definition metrics.hpp:231
Definition exceptions.hpp:22
Plain value snapshots of the live state of the ThreadMan world — threads, pools, tasks,...
A snapshot of a future-state object. Useful for diagnostics.
Definition stats.hpp:91
bool shared
Definition stats.hpp:95
std::uint32_t continuation_count
Definition stats.hpp:94
bool has_exception
Definition stats.hpp:93
bool ready
Definition stats.hpp:92
Definition future.hpp:55
std::optional< T > value
Definition future.hpp:56