add thread-safe dispatcher callback mechanism#694
Open
arnetheduck wants to merge 8 commits into
Open
Conversation
`callSoon` currently is well-defined for the current thread but cannot be called from a different thread. `ThreadSignalPtr` can be used to overcome this limitation but comes with the significant downside that each signal requires its own file descriptor / handle - while this approach works for specific cases it becomes costly in a general-purpose setting such as https://github.com/status-im/nim-async-channels where each channel ends up needing its own instance. It would in theory be possible to use a thread-local `ThreadSignalPtr` for channels in particular, but this would still not achieve the higher goal of sharing a single wake-up / notification mechanism per event loop instance. A thread-safe `callSoon` allows threads to post work to the dispatcher of another thread and getting called back from within the scope of that thread "soon" - for example, in the AsyncChannel when a reader appears and the channel is empty, the reader can register its own dispatcher with the channel so that when a queue item appears, the channel can wake up the corresponding dispatcher and complete the future from within the correct thread-local context. A simple unbounded MPSC queue is used for storing cross-thread callbacks - the cost is roughly equivalent to the existing `AsyncCallback` when used with a closure environment, ie one allocation per posted work item plus whatever the caller needs. The design does not depend on the specific queue being used, ie a future version could use a ring buffer + a spill queue or similar designs that reduce allocations. Coupled with the queue is a cross-platform "wakeup" mechanism similar to the one used in `ThreadSignalPtr` - when a callback is posted to the queue, we also make sure to wake up the dispatcher so that indeed the callback happens "soon".
arnetheduck
force-pushed
the
thread-call-soon
branch
from
July 21, 2026 10:30
77b665d to
6e1d066
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
callSooncurrently is well-defined for the current thread but cannot be called from a different thread.ThreadSignalPtrcan be used to overcome this limitation but comes with the significant downside that each signal requires its own file descriptor / handle - while this approach works for specific cases it becomes costly in a general-purpose setting such as https://github.com/status-im/nim-async-channels where each channel ends up needing its own instance.It would in theory be possible to use a thread-local
ThreadSignalPtrfor channels in particular, but this would still not achieve the higher goal of sharing a single wake-up / notification mechanism per event loop instance.A thread-safe
callSoonallows threads to post work to the dispatcher of another thread and getting called back from within the scope of that thread "soon" - for example, in the AsyncChannel when a reader appears and the channel is empty, the reader can register its own dispatcher with the channel so that when a queue item appears, the channel can wake up the corresponding dispatcher and complete the future from within the correct thread-local context.A simple unbounded MPSC queue is used for storing cross-thread callbacks - the cost is roughly equivalent to the existing
AsyncCallbackwhen used with a closure environment, ie one allocation per posted work item plus whatever the caller needs.The design does not depend on the specific queue being used, ie a future version could use a ring buffer + a spill queue or similar designs that reduce allocations.
Coupled with the queue is a cross-platform "wakeup" mechanism similar to the one used in
ThreadSignalPtr- when a callback is posted to the queue, we also make sure to wake up the dispatcher so that indeed the callback happens "soon".