Thread Dispatching¶
Nalix.SDK uses a lightweight IThreadDispatcher interface to bridge the gap between high-performance background networking threads and single-threaded application contexts like UI frameworks or game engines.
Dispatch Flow¶
sequenceDiagram
participant N as Network Thread
participant D as IThreadDispatcher
participant M as Main/UI Thread
Note over N: Packet Received
N->>D: Post(UpdateAction)
D->>M: BeginInvoke / Queue
Note over M: UpdateAction Executed
M->>M: Update UI / Scene
Source mapping¶
src/Nalix.SDK/IThreadDispatcher.cssrc/Nalix.SDK/InlineDispatcher.cs
Role and Design¶
Networking in Nalix is naturally asynchronous and runs on dedicated background threads. However, most UI frameworks (WPF, MAUI, WinForms) and game engines (Unity, Godot) restrict state changes to a specific "Main Thread".
IThreadDispatcher provides a clean abstraction to marshal these background callbacks back to the safe thread without coupling the core SDK to any specific platform.
- Minimal Surface: Only one method (
Post) to maintain maximum compatibility. - Pluggable: Easily swap between platform-specific dispatchers during application startup.
- Transparent: The
InlineDispatcheris provided for headless or console applications where thread marshalling is unnecessary.
Implementation Examples¶
Unity (Main Thread)¶
public sealed class UnityDispatcher : IThreadDispatcher
{
public void Post(Action action) => UnityMainThreadDispatcher.Enqueue(action);
}
.NET MAUI¶
public sealed class MauiDispatcher : IThreadDispatcher
{
public void Post(Action action) => MainThread.BeginInvokeOnMainThread(action);
}
WPF / WinForms (SynchronizationContext)¶
public sealed class SynchronizationContextDispatcher : IThreadDispatcher
{
private readonly SynchronizationContext _context = SynchronizationContext.Current;
public void Post(Action action) => _context.Post(_ => action(), null);
}
Basic usage¶
IThreadDispatcher dispatcher = GetPlatformDispatcher();
client.OnMessageReceived += (s, lease) =>
{
// We are on a background thread here
dispatcher.Post(() =>
{
// Now safely on the Main Thread
myLabel.Text = "Updated!";
});
};
Common pitfalls¶
- Direct UI Mutation: Forgetting to use
Postand touching UI components directly will typically cause a cross-thread exception or a silent crash. - Deadlocks: Avoid using
BlockingCollectionor synchronous waits inside the dispatched action. - Capturing Scoped Data: Be careful when capturing variables in the
Postlambda; ensure they are still valid when the action eventually runs.