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 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 {
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 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
83private:
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