userver: userver/engine/single_use_event.hpp Source File
Loading...
Searching...
No Matches
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 task 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 {
46public:
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 task 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 task that waits on it, if any.
72 /// `Send` must not be called again.
73 ///
74 /// You can safely invoke Send from outside a coroutine.
75 void Send() noexcept;
76
77 /// Returns true iff already signaled.
78 [[nodiscard]] bool IsReady() const noexcept override;
79
80 /// @cond
81 // For internal use only.
82 impl::ContextAccessor* TryGetContextAccessor() noexcept { return this; }
83 /// @endcond
84
85private:
86 friend class impl::FutureWaitStrategy<SingleUseEvent>;
87
88 impl::EarlyWakeup TryAppendWaiter(impl::TaskContext& waiter) override;
89 void RemoveWaiter(impl::TaskContext& waiter) noexcept override;
90 void RethrowErrorResult() const override;
91 void AfterWait() noexcept override;
92
93 impl::FastPimplWaitListLight waiters_;
94};
95
96} // namespace engine
97
98USERVER_NAMESPACE_END