userver: engine::SingleConsumerEvent Class Reference
Loading...
Searching...
No Matches
engine::SingleConsumerEvent Class Referencefinal

#include <userver/engine/single_consumer_event.hpp>

Detailed Description

A multiple-producers, single-consumer event.

Definition at line 19 of file single_consumer_event.hpp.

Classes

struct  NoAutoReset
 

Public Member Functions

 SingleConsumerEvent () noexcept
 Creates an event that resets automatically on retrieval.
 
 SingleConsumerEvent (NoAutoReset) noexcept
 Creates an event that does not reset automatically.
 
 SingleConsumerEvent (const SingleConsumerEvent &)=delete
 
 SingleConsumerEvent (SingleConsumerEvent &&)=delete
 
SingleConsumerEventoperator= (const SingleConsumerEvent &)=delete
 
SingleConsumerEventoperator= (SingleConsumerEvent &&)=delete
 
bool IsAutoReset () const noexcept
 
bool WaitForEvent ()
 Waits until the event is in a signaled state.
 
template<typename Clock , typename Duration >
bool WaitForEventFor (std::chrono::duration< Clock, Duration >)
 
template<typename Clock , typename Duration >
bool WaitForEventUntil (std::chrono::time_point< Clock, Duration >)
 
bool WaitForEventUntil (Deadline)
 
template<typename Predicate >
bool WaitUntil (Deadline, Predicate stop_waiting)
 Works like std::condition_variable::wait_until. Waits until stop_waiting becomes true, and we are notified via Send.
 
void Reset () noexcept
 
void Send ()
 
bool IsReady () const noexcept
 Returns true iff already signaled. Never resets the signal.
 

Member Function Documentation

◆ IsAutoReset()

bool engine::SingleConsumerEvent::IsAutoReset ( ) const
noexcept
Returns
whether this event resets automatically on retrieval

◆ Reset()

void engine::SingleConsumerEvent::Reset ( )
noexcept

Resets the signal flag. Guarantees at least 'acquire' and 'release' memory ordering. Must only be called by the waiting task.

◆ Send()

void engine::SingleConsumerEvent::Send ( )

Sets the signal flag and wakes a coroutine that waits on it (if any). If the signal flag is already set, does nothing.

The waiter is allowed to destroy the SingleConsumerEvent immediately after exiting WaitForEvent, ONLY IF the wait succeeded. Otherwise a concurrent task may call Send on a destroyed SingleConsumerEvent. Here is an example of this situation:

{
sender = engine::AsyncNoSpan([&event] { event.Send(); });
// will be woken up by 'Send()' above
const bool success = event.WaitForEvent();
if (!success) {
// If the waiting failed due to deadline or cancellation, we must somehow
// wait until the parallel task does Send (or prevent the parallel task
// from ever doing Send) before destroying the SingleConsumerEvent.
sender.SyncCancel();
}
// 'event' is destroyed here. Note that 'Send' might continue executing, but
// it will still complete safely.
}

◆ WaitForEvent()

bool engine::SingleConsumerEvent::WaitForEvent ( )

Waits until the event is in a signaled state.

If the event is auto-resetting, clears the signal flag upon waking up. If already in a signaled state, does the same without sleeping.

If we the waiting failed (the event did not signal), because the optional deadline is expired or the current task is cancelled, returns false.

Returns
whether the event signaled

This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.

◆ WaitForEventFor()

template<typename Clock , typename Duration >
bool engine::SingleConsumerEvent::WaitForEventFor ( std::chrono::duration< Clock, Duration > duration)

Definition at line 113 of file single_consumer_event.hpp.

◆ WaitForEventUntil()

template<typename Clock , typename Duration >
bool engine::SingleConsumerEvent::WaitForEventUntil ( std::chrono::time_point< Clock, Duration > time_point)

Definition at line 118 of file single_consumer_event.hpp.

◆ WaitUntil()

template<typename Predicate >
bool engine::SingleConsumerEvent::WaitUntil ( Deadline deadline,
Predicate stop_waiting )

Works like std::condition_variable::wait_until. Waits until stop_waiting becomes true, and we are notified via Send.

If stop_waiting` is already true, returns right away.

Unlike std::condition_variable and engine::ConditionVariable, there are no locks around the state watched by stop_waiting, so that state must be atomic. std::memory_order_relaxed is OK inside stop_waiting and inside the notifiers as long as it does not mess up their logic.

Example. Suppose we want to wait until a counter is even, then grab it.

Initialization:

std::atomic<std::uint64_t> count{1};

Notifier side:

// First, mutate the state.
// Notifiers and the waiter will access the state in parallel.
// Operations must be atomic, can be std::memory_order_relaxed.
count.fetch_add(1, std::memory_order_relaxed);
// Second, notify the waiter.
event.Send();

Waiter side:

std::uint64_t count_acquired{};
const bool success = event.WaitUntil({}, [&] {
// Operations must be atomic, can be std::memory_order_relaxed.
count_acquired = count.load(std::memory_order_relaxed);
return count_acquired % 2 == 0 && count.compare_exchange_strong(count_acquired, 0, std::memory_order_relaxed);
});

Definition at line 123 of file single_consumer_event.hpp.


The documentation for this class was generated from the following file: