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