userver: userver/engine/multi_consumer_event.hpp Source File
Loading...
Searching...
No Matches
multi_consumer_event.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/engine/multi_consumer_event.hpp
4/// @brief @copybrief engine::MultiConsumerEvent
5
6#include <atomic>
7
8#include <userver/compiler/impl/lifetime.hpp>
9#include <userver/engine/awaitable.hpp>
10#include <userver/engine/deadline.hpp>
11#include <userver/engine/future_status.hpp>
12#include <userver/engine/impl/context_accessor.hpp>
13#include <userver/engine/impl/wait_list_fwd.hpp>
14#include <userver/utils/fast_pimpl.hpp>
15#include <userver/utils/impl/internal_tag.hpp>
16
17USERVER_NAMESPACE_BEGIN
18
19namespace engine {
20
21/// @ingroup userver_concurrency
22///
23/// @brief A single-producer, multiple-consumers event.
24///
25/// Once the producer sends the event, it remains in the signaled state forever.
26///
27/// Compatible with @ref engine::WaitAny and friends.
28///
29/// ## Destroying a MultiConsumerEvent after waking up
30///
31/// Unlike @ref engine::SingleUseEvent, `MultiConsumerEvent` has multiple consumers, thus a consumer is not allowed to
32/// destroy `MultiConsumerEvent` instance, instead the producer should be responsible for that.
33///
34/// @see @ref scripts/docs/en/userver/synchronization.md
35class MultiConsumerEvent final : private impl::AwaitableBase {
36public:
37 MultiConsumerEvent() noexcept;
38
39 MultiConsumerEvent(const MultiConsumerEvent&) = delete;
40 MultiConsumerEvent(MultiConsumerEvent&&) = delete;
41 MultiConsumerEvent& operator=(const MultiConsumerEvent&) = delete;
42 MultiConsumerEvent& operator=(MultiConsumerEvent&&) = delete;
43 ~MultiConsumerEvent();
44
45 /// @brief Waits until the event is in a signaled state.
46 ///
47 /// @throws engine::WaitInterruptedException if the current task is cancelled
48 void Wait();
49
50 /// @brief Waits until the event is in a signaled state, or the deadline
51 /// expires, or the current task is cancelled.
52 [[nodiscard]] FutureStatus WaitUntil(Deadline);
53
54 /// Sets the signal flag and wakes tasks that wait on it, if any.
55 /// `Send` must not be called again.
56 ///
57 /// You can safely invoke Send from outside a coroutine.
58 void Send() noexcept;
59
60 /// Returns true if already signaled.
61 [[nodiscard]] bool IsReady() const noexcept override;
62
63 /// Satisfies @ref engine::Awaitable, for use with @ref engine::WaitAnyContext and friends.
64 AwaitableToken GetAwaitableToken() noexcept USERVER_IMPL_LIFETIME_BOUND {
65 return AwaitableToken{utils::impl::InternalTag{}, this};
66 }
67
68private:
69 void TryAppendAwaiter(impl::AwaiterPtr& awaiter, std::uintptr_t context) override;
70 impl::AwaiterPtr RemoveAwaiter(impl::Awaiter& awaiter, std::uintptr_t context) noexcept override;
71
72 std::atomic<bool> is_ready_{false};
73 impl::FastPimplWaitList awaiters_;
74};
75
76} // namespace engine
77
78USERVER_NAMESPACE_END