ProtocolActor Class¶
Default IProtocolActor: one mailbox (System.Collections.Concurrent.ConcurrentQueue<> of work items), one loop, one sorted list of pending timers — both owned exclusively by whichever thread is currently running the loop, so neither needs its own lock (FR-RAW-020/021). The loop blocks on a SemaphoreSlim for either new mailbox work or the next timer deadline, whichever comes first, and never polls (FR-RAW-022). Any exception from a posted work item or a fired timer is caught and raised via BackgroundExceptionOccurred; the loop keeps running afterward (FR-RAW-023).
Inheritance Object → ProtocolActor
Implements IProtocolActor, IDisposable
Constructors¶
ProtocolActor(ActorExecutionMode, SynchronizationContext) Constructor¶
Creates an actor and immediately starts its mailbox loop under mode.
public ProtocolActor(CanKit.Pro.Actor.ActorExecutionMode mode=CanKit.Pro.Actor.ActorExecutionMode.DedicatedThread, System.Threading.SynchronizationContext? synchronizationContext=null);
Parameters¶
mode ActorExecutionMode
Execution context for the loop (FR-RAW-024). Defaults to a dedicated thread.
synchronizationContext SynchronizationContext
Required when mode is SynchronizationContext; must be null for every other mode.
Properties¶
ProtocolActor.IsOnCurrentActor Property¶
True when <i>the calling thread</i> is currently executing a work item or timer callback belonging to this actor, false otherwise.
Property Value¶
Remarks¶
Lets a public sync API safely detect that it is already on the actor loop and run the requested work inline instead of routing it through PostAsync(Action) and synchronously waiting on the returned task — which would deadlock the loop against itself. External callers still take the marshal-through-mailbox path exactly as before.
Thread-scoped, deliberately: a Task started from inside a callback runs on
a different thread and reports false, because it genuinely is not on the actor
and must not mutate actor state inline. (Backing this with an
System.Threading.AsyncLocal<> instead would flow the flag into every such task through the
ExecutionContext and report true there — the bug this property is
most likely to be trusted with preventing.) In
SynchronizationContext mode the flag is set on whichever
thread the context actually runs the callback on, so it stays correct there too.
Methods¶
ProtocolActor.Post(Action) Method¶
Enqueues work to run on the actor's mailbox loop and returns immediately ("tell" / fire-and-forget). If work throws, the exception is caught by the loop and surfaced via BackgroundExceptionOccurred — there is no other way for a fire-and-forget caller to observe it (FR-RAW-023).
Parameters¶
work Action
Implements Post(Action)
ProtocolActor.PostAsync(Action) Method¶
Enqueues work to run on the actor's mailbox loop and returns a task that completes once it has run ("ask"). Unlike Post(Action), an exception from work is surfaced through the returned task's fault, not through BackgroundExceptionOccurred — the caller is already positioned to observe it by awaiting.
Parameters¶
work Action
Implements PostAsync(Action)
Returns¶
ProtocolActor.PostAsync<T>(Func<T>) Method¶
Same as PostAsync(Action) but returns work's result.
Type parameters¶
T
Parameters¶
Implements PostAsync<T>(Func<T>)
Returns¶
ProtocolActor.Schedule(TimeSpan, Action) Method¶
Schedules callback to run on the actor's mailbox loop once delay has elapsed, using event-driven waiting rather than polling (FR-RAW-022) — suitable for STmin waits, timeout checks, and similar periodic/timed protocol tasks. Disposing the returned handle cancels the callback on a best-effort basis: it will not fire if cancellation is observed before it becomes due, but a callback already in flight on the loop may still complete.
Parameters¶
delay TimeSpan
callback Action
Implements Schedule(TimeSpan, Action)
Returns¶
Events¶
ProtocolActor.BackgroundExceptionOccurred Event¶
Raised whenever a posted work item (via Post(Action)) or a scheduled callback (via Schedule(TimeSpan, Action)) throws — the actor's single, defined channel for background exceptions (FR-RAW-023). The mailbox loop keeps running afterward; one failing item never stops the actor. Never raised for PostAsync(Action)/ PostAsync<T>(Func<T>) failures, which surface through their own returned task instead.
Implements BackgroundExceptionOccurred