Let's say I have a UI thread and a background thread that subscribe to a custom thread-safe ObservableCollection that I created so that whenever the collection changes it executes the callback within the appropriate context.
Now let's say I add something to the collection (from either thread, doesn't matter which one) and it now has to marshall the callback to both threads. To execute the callback within the UI's context I can simply do a Dispatcher.Invoke(...) and it executes the callback within the UI's context; great.
Now I want to execute the callback within the background thread's context (don't ask me why, it may well be that whatever it's accessing is affinitized to that specific thread or has thread-local storage it needs to access); how would I do that?
Background threads don't have a dispatcher/message pumping mechanism so I can't use a dispatcher or SynchronizationContext, so how would one interrupt a background thread and have it execute my callback within its context?
EDIT: I keep getting answers that are obviously wrong so I must not have explained myself correctly. Forget the UI thread and UI dispatchers guys, they were meant to marshall calls to the UI thread, that's it! Imagine two worker threads A and B. If A modifies my collection then A is in charge of marshalling the callback to itself and to B. Executing the callback within A's context is easy since A was the one triggering it : simply call the delegate in place. Now A needs to marshall the callback to B... now what? Dispatcher and SynContext are useless in this situation.
We have a component that must always run on the same STA background thread. We've achieved this by writing our own
SynchronizationContext
. This article is very helpful.To summarise, you don't want to interrupt your worker thread, you want it to sit idle waiting for the next task that it should execute. You add jobs to a queue and it processes those jobs in order. The
SynchronizationContext
is a convenient abstraction around that idea. TheSynchronizationContext
is the owner of the worker thread - and the outside world does not interact with the thread directly: callers who want to execute a task on the worker thread make the request to the context which adds the job to the job queue. The worker is either working or polling the queue until another job is added, at which point it begins working again.Update
Here is an example:
Usage:
The
Send
case is slightly more involved as you will need to listen for a reset event.. This is not production quality, but should give you an idea ow what you need to do.Hope that helps.
A good idea might also be extending your own TaskScheduler, you will have to implement three methods:
QueueTask, TryExecuteTaskInline and GetScheduledTasks
you can read about it here
That way, anytime you need to run something on your dedicated thread you could just do:
and have it execute on your thread.
I'd use two task schedulers for this (as @YuvalItzchakov's answer suggests), one for each thread. I'd also use a custom synchronization context for the worker thread, as @TheMouthofaCow's answer suggests.
That is, for a UI thread, I'd just save and use
TaskScheduler.FromCurrentSynchronizationContext()
. For the worker thread, I would start a thread and install a custom synchronization context on it, then useFromCurrentSynchronizationContext
too.Something like this (untested):
This give you some sort of cooperative asynchronous execution between two threads.