Note first of all that this question is not tagged winforms or wpf or anything else GUI-specific. This is intentional, as you will see shortly.
Second, sorry if this question is somewhat long. I try to pull together various bits of information floating around here and there so as to also provide valuable information. My question, however, is right under "What I would like to know".
I'm on a mission to finally understand the various ways offered by .NET to invoke a delegate on a specific thread.
What I would like to know:
I am looking for the most general way possible (that is not Winforms or WPF-specific) to invoke delegates on specific threads.
Or, phrased differently: I would be interested if, and how, the various ways to do this (such as via WPF's
Dispatcher
) make use of each other; that is, if there is one common mechanism for cross-thread delegate invocation that's used by all the others.
What I know already:
There's many classes related to this topic; among them:
SynchronizationContext
(inSystem.Threading
)
If I had to guess, that would be the most basic one; although I don't understand what exactly it does, nor how it is used.AsyncOperation
&AsyncOperationManager
(inSystem.ComponentModel
)
These seem to be wrappers aroundSynchronizationContext
. No clue how to use them.WindowsFormsSynchronizationContext
(inSystem.Windows.Forms
)
A subclass ofSynchronizationContext
.ISynchronizeInvoke
(inSystem.ComponentModel
)
Used by Windows Forms. (TheControl
class implements this. If I'd have to guess, I'd say this implementation makes use ofWindowsFormsSynchronizationContext
.)Dispatcher
&DispatcherSynchronizationContext
(inSystem.Windows.Threading
)
Seems like the latter is another subclass ofSynchronizationContext
, and the former delegates to it.
Some threads have their own message loop, along with a message queue.
(The MSDN page About Messages and Message Queues has some introductory background information on how message loops work at the system level, i.e. message queues as the Windows API.)
I can see how one would implement cross-thread invocation for threads with a message queue. Using the Windows API, you would put a message into a specific thread's message queue via
PostThreadMessage
that contains an instruction to call some delegate. The message loop — which runs on that thread — will eventually get to that message, and the delegate will be called.From what I've read on MSDN, a thread doesn't automatically have its own message queue. A message queue will become available e.g. when a thread has created a window. Without a message queue, it doesn't make sense for a thread to have a message loop.
So, is cross-thread delegate invocation possible at all when the target thread has no message loop? Let's say, in a .NET console application? (Judging from the answers to this question, I suppose it's indeed impossible with console apps.)
QueueSyncContext.Send
is incorrect, because it invokes the delegate on the caller's thread. The intent ofSend
is to block the caller while the delegate runs on the thread represented by the SynchronizationContext. This ensures that the delegate accesses the right thread-local objects, doesn't run at the same time as other delegates invoked via Send or Post (to avoid race conditions), etc. (Note that this doesn't apply to free-threaded sync contexts that e.g., run delegates on the threadpool, but I didn't think this was your intent here.) – Meredithmeredithe