userver: userver/engine/single_use_event.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
single_use_event.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/engine/single_use_event.hpp
4/// @brief @copybrief engine::SingleUseEvent
5
6#include <userver/engine/deadline.hpp>
7#include <userver/engine/future_status.hpp>
8#include <userver/engine/impl/context_accessor.hpp>
9#include <userver/engine/impl/wait_list_fwd.hpp>
10#include <userver/utils/fast_pimpl.hpp>
11
12USERVER_NAMESPACE_BEGIN
13
14namespace engine {
15
16/// @ingroup userver_concurrency
17///
18/// @brief A single-producer, single-consumer event.
19///
20/// Once the producer sends the event, it remains in the signaled state forever.
21///
22/// SingleUseEvent can be used as a faster non-allocating alternative
23/// to engine::Future. However, it is more low-level and error-prone, see below.
24///
25/// Compatible with engine::WaitAny and friends.
26///
27/// ## Destroying a SingleUseEvent after waking up
28///
29/// The waiting coroutine is allowed to immediately destroy the `SingleUseEvent`
30/// after waking up; it will not stop a concurrent `Send` from completing
31/// correctly. This is contrary to the properties of other userver
32/// synchronization primitives, like engine::Mutex.
33///
34/// However, if the wait operation ends in something other than
35/// engine::Future::kReady, then it is the responsibility of the waiter
36/// to guarantee that it either prevents the oncoming `Send` call or awaits it.
37/// One way to force waiting until the `Send` call happens is to use
38/// engine::SingleUseEvent::WaitNonCancellable.
39///
40/// ## Example usage
41///
42/// @snippet engine/single_use_event_test.cpp Wait and destroy
43///
44/// @see @ref scripts/docs/en/userver/synchronization.md
45class SingleUseEvent final : private impl::ContextAccessor {
46 public:
47 SingleUseEvent() noexcept;
48
49 SingleUseEvent(const SingleUseEvent&) = delete;
50 SingleUseEvent(SingleUseEvent&&) = delete;
51 SingleUseEvent& operator=(const SingleUseEvent&) = delete;
52 SingleUseEvent& operator=(SingleUseEvent&&) = delete;
53 ~SingleUseEvent();
54
55 /// @brief Waits until the event is in a signaled state.
56 ///
57 /// @throws engine::WaitInterruptedException if the current task is cancelled
58 void Wait();
59
60 /// @brief Waits until the event is in a signaled state, or the deadline
61 /// expires, or the current task is cancelled.
62 [[nodiscard]] FutureStatus WaitUntil(Deadline);
63
64 /// @brief Waits until the event is in a signaled state, ignoring task
65 /// cancellations.
66 ///
67 /// The waiter coroutine can destroy the `SingleUseEvent` object immediately
68 /// after waking up, if necessary.
69 void WaitNonCancellable() noexcept;
70
71 /// Sets the signal flag and wakes a coroutine that waits on it, if any.
72 /// `Send` must not be called again.
73 void Send() noexcept;
74
75 /// Returns true iff already signaled.
76 [[nodiscard]] bool IsReady() const noexcept override;
77
78 /// @cond
79 // For internal use only.
80 impl::ContextAccessor* TryGetContextAccessor() noexcept { return this; }
81 /// @endcond
82
83 private:
84 friend class impl::FutureWaitStrategy<SingleUseEvent>;
85
86 impl::EarlyWakeup TryAppendWaiter(impl::TaskContext& waiter) override;
87 void RemoveWaiter(impl::TaskContext& waiter) noexcept override;
88 void RethrowErrorResult() const override;
89 void AfterWait() noexcept override;
90
91 impl::FastPimplWaitListLight waiters_;
92};
93
94} // namespace engine
95
96USERVER_NAMESPACE_END