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