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/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
14USERVER_NAMESPACE_BEGIN
15
16namespace engine {
17
18namespace impl {
19
20template <typename T>
21class FutureWaitStrategy;
22
23} // namespace impl
24
25/// @ingroup userver_concurrency
26///
27/// @brief A single-producer, multiple-consumers event.
28///
29/// Once the producer sends the event, it remains in the signaled state forever.
30///
31/// Compatible with @ref engine::WaitAny and friends.
32///
33/// ## Destroying a MultiConsumerEvent after waking up
34///
35/// Unlike @ref engine::SingleUseEvent, `MultiConsumerEvent` has multiple consumers, thus a consumer is not allowed to
36/// destroy `MultiConsumerEvent` instance, instead the producer should be responsible for that.
37///
38/// @see @ref scripts/docs/en/userver/synchronization.md
39class MultiConsumerEvent final : private impl::ContextAccessor {
40public:
41 MultiConsumerEvent() noexcept;
42
43 MultiConsumerEvent(const MultiConsumerEvent&) = delete;
44 MultiConsumerEvent(MultiConsumerEvent&&) = delete;
45 MultiConsumerEvent& operator=(const MultiConsumerEvent&) = delete;
46 MultiConsumerEvent& operator=(MultiConsumerEvent&&) = delete;
47 ~MultiConsumerEvent();
48
49 /// @brief Waits until the event is in a signaled state.
50 ///
51 /// @throws engine::WaitInterruptedException if the current task is cancelled
52 void Wait();
53
54 /// @brief Waits until the event is in a signaled state, or the deadline
55 /// expires, or the current task is cancelled.
56 [[nodiscard]] FutureStatus WaitUntil(Deadline);
57
58 /// Sets the signal flag and wakes tasks that wait on it, if any.
59 /// `Send` must not be called again.
60 ///
61 /// You can safely invoke Send from outside a coroutine.
62 void Send() noexcept;
63
64 /// Returns true if already signaled.
65 [[nodiscard]] bool IsReady() const noexcept override;
66
67 /// @cond
68 // For internal use only.
69 impl::ContextAccessor* TryGetContextAccessor() noexcept { return this; }
70 /// @endcond
71
72private:
73 friend class impl::FutureWaitStrategy<MultiConsumerEvent>;
74
75 void TryAppendAwaiter(boost::intrusive_ptr<impl::Awaiter>& awaiter, std::uintptr_t context) override;
76 void RemoveAwaiter(impl::Awaiter& awaiter, std::uintptr_t context) noexcept override;
77
78 std::atomic<bool> is_ready_{false};
79 impl::FastPimplWaitList awaiters_;
80};
81
82} // namespace engine
83
84USERVER_NAMESPACE_END