Event count¶
A standalone adaptation of folly::EventCount
utilizing C++20’s atomic wait facilities.
This file has been adapted from:
-
class event_count : private lf::impl::immovable<event_count>¶
A condition variable for lock free algorithms.
See http://www.1024cores.net/home/lock-free-algorithms/eventcounts for details.
Event counts allow you to convert a non-blocking lock-free / wait-free algorithm into a blocking one, by isolating the blocking logic. You call prepare_wait() before checking your condition and then either cancel_wait() or wait() depending on whether the condition was true. When another thread makes the condition true, it must call notify() / notify_all() just like a regular condition variable.
If “<” denotes the happens-before relationship, consider 2 threads (T1 and T2) and 3 events:
E1: T1 returns from prepare_wait.
E2: T1 calls wait (obviously E1 < E2, intra-thread).
E3: T2 calls
notify_all()
.
If E1 < E3, then E2’s wait will complete (and T1 will either wake up, or not block at all)
This means that you can use an event_count in the following manner:
Waiter:
if (!condition()) { // handle fast path first for (;;) { auto key = eventCount.prepare_wait(); if (condition()) { eventCount.cancel_wait(); break; } else { eventCount.wait(key); } } }
(This pattern is encapsulated in the
await()
method.)Poster:
make_condition_true(); eventCount.notify_all();
Note
Just like with regular condition variables, the waiter needs to be tolerant of spurious wakeups and needs to recheck the condition after being woken up. Also, as there is no mutual exclusion implied, “checking” the condition likely means attempting an operation on an underlying data structure (push into a lock-free queue, etc) and returning true on success and false on failure.
Public Functions
-
template<typename Pred>
void await(Pred const &condition) noexcept(std::is_nothrow_invocable_r_v<bool, Pred const&>)¶ Wait for
condition()
to become true.Cleans up appropriately if
condition()
throws, and then rethrow.
-
inline auto cancel_wait() noexcept -> void¶
Cancel a wait that was prepared with
prepare_wait()
.
-
inline auto notify_all() noexcept -> void¶
Wake up all waiters.
-
inline auto notify_one() noexcept -> void¶
Wake up one waiter.
-
inline auto prepare_wait() noexcept -> key¶
Prepare to wait.
Once this has been called, you must either call
wait()
with the key orcancel_wait()
.
-
class key¶
The return type of
prepare_wait()
.