|
JH-Toolkit v1.4.1
An engineering-oriented C++20 toolkit with duck-typed concepts, static design, async coroutines, and semantic containers — header-only, RTTI-free, and concurrency-friendly.
|
Coroutine representing the user-defined asynchronous state machine. More...
#include <jh/asynchronous/slot.h>
Classes | |
| struct | promise_type |
| Slot coroutine promise type. More... | |
Public Member Functions | |
| slot ()=default | |
| Default constructor for slot. | |
| slot (slot &&o) noexcept | |
| Move constructor transferring coroutine handle ownership. | |
| slot & | operator= (slot &&o) noexcept |
| Move assignment operator transferring coroutine handle ownership. | |
| slot (const slot &)=delete | |
| Copy constructor is deleted to prevent duplication of coroutine handle. | |
| slot & | operator= (const slot &)=delete |
| Copy assignment is deleted to prevent unsafe copying of coroutine handle. | |
| void | spawn () |
| Start the coroutine associated with this slot. | |
Friends | |
| template<typename T> | |
| class | listener |
| Grants listener<T> access to internal slot members. | |
Coroutine representing the user-defined asynchronous state machine.
A slot is the only execution context of the entire "slot-listener-signal" system. It defines the state machine, phase switching, routing, filtering, and fan-out logic. A slot always runs on the thread where spawn() is invoked.
A slot may suspend on exactly one listener at any time. Each co_await represents one logical synchronous step.
Awaiting multiple listeners inside the same loop is technically idempotent per iteration but semantically meaningless, because this requires the external event sources to be strictly time-aligned. If external producers drift in timing (which is unavoidable in real-time systems), the synchronous semantics break immediately.
In other words, the following pattern is strongly discouraged:
This is irrelevant to our implementation. Semantically, asynchronous operations always perform triggering and consuming.
In other words, the discouraged behavior implies a sync-barrier semantic. This means that if any listener is advancing too rapidly and resumes two or more times before the other listener resumes even once in the same iteration, the state machine is broken.
According to the C++20 coroutine model, if you want to guarantee the correctness of this behavior, then you need external synchronization; that maps to sync-barrier rather than async-resuming.
However, If a user truly has perfectly time-aligned external timing, then the recommended design is:
event_signal to emit a tuple containing all values needed for that round. In summary, this behavior is semantically determined and implementation-independent. If you need to observe multiple input sources in the same logical step, then it's fan-in, see listener.
Multiple listeners exist for different phases or different conditions, not for parallel waiting. A slot typically performs:
slot, slot_hub, and listeners must share unified lifetime. co_yield {} returns an empty sentinel value (jh::typed::monostate). This is not necessarily needed, but ensures consistency on non-main threads. It can also be used as a jump point (similar to return in a regular function). co_await listener and the next declared co_await another_listener.
|
inline |
Start the coroutine associated with this slot.
Transitions the coroutine from the initial suspended state to active execution. It binds the coroutine to the current thread permanently. This function is only effective once.