Lock-free publication to a reader that must never block. More...
#include <slot.hpp>
Classes | |
| class | ReadGuard |
| RAII pin. More... | |
Public Member Functions | |
| Slot ()=default | |
| Slot (const Slot &)=delete | |
| Slot & | operator= (const Slot &)=delete |
| ~Slot () | |
| Blocks until every reader has left, then frees everything. | |
| ReadGuard | read () const noexcept |
| Audio-thread-callable. | |
| void | prepare_publish () |
| Publisher thread. | |
| void | publish_prepared (std::shared_ptr< T > next) noexcept |
| Publish after prepare_publish(). | |
| void | publish (std::shared_ptr< T > next) |
| void | publish (std::unique_ptr< T > next) |
| void | unpublish () |
| Publisher thread. | |
| void | reclaim_if_quiescent () |
| Publisher thread. | |
| void | wait_and_clear () |
| Publisher thread, teardown only. | |
| const std::shared_ptr< T > & | live () const noexcept |
| Publisher thread only. | |
| std::size_t | retired_count () const noexcept |
| Number of displaced values still awaiting reclamation. | |
| bool | has_value () const noexcept |
| True once something has been published. | |
Lock-free publication to a reader that must never block.
The reader pins the slot for the duration of its access; the writer swaps in a new value and parks the old one until every reader has left.
Slot manages the published object's LIFETIME, not its constness. A pin guarantees only that the object will not be destroyed while you hold it. RCU is a reclamation scheme, not an immutability scheme.
That distinction is load-bearing. SignalGraph's published CompiledGraph is emphatically not immutable: the audio thread writes every node's scratch buffer through it on every block, and control-thread readers drain telemetry and inject MIDI through the same pin. What is immutable is the topology. If you want a genuinely read-only value, say so in the type — Slot<const T> — and the guard hands back const T* for free.
The audio thread's cost is one seq_cst increment, one atomic load, and one seq_cst decrement. No allocation, no destructor, no lock.
|
default |
|
delete |
|
inline |
Blocks until every reader has left, then frees everything.
Publisher thread only, and only once both sides have stopped racing to publish.
|
inlinenoexcept |
True once something has been published.
|
inlinenoexcept |
|
delete |
|
inline |
Publisher thread.
Swap in a new value; the displaced one is parked and freed as soon as no reader holds it. Publishing nullptr unpublishes. Publisher-thread allocation preflight for publish_prepared(). Call this before an external transaction reaches its irreversible commit point. Any allocation failure is reported here, while all external state is still untouched.
|
inline |
|
inline |
|
inlinenoexcept |
Publish after prepare_publish().
This operation cannot allocate or throw, so it is safe to pair immediately after an external commit.
|
inlinenodiscardnoexcept |
Audio-thread-callable.
Pin and read the currently published value. Returns a falsy guard when nothing has been published yet.
RT contract: never allocates, never blocks, never frees.
|
inline |
Publisher thread.
Free any parked values if no reader is currently inside read(). Non-blocking: does nothing when a reader is active. Call it opportunistically (e.g. after each block) to bound memory.
|
inlinenoexcept |
Number of displaced values still awaiting reclamation.
|
inline |
Publisher thread.
Drop the published value: readers immediately see nothing, and the displaced value is reclaimed once they drain.
Spelled out rather than publish(nullptr) — which is ambiguous between the two overloads above, and reads worse at the call site.
|
inline |
Publisher thread, teardown only.
Spins until readers drain, then frees. Never call this from the audio thread.