Nothing like that.
First of all, what you call main thread is more usually called UI thread.
Control.Invoke
and
Control.BeginInvoke
work in any thread. The functionality is completely insensitive to the origin of the thread: it can be UI thread, a thread created through
System.Threading.Thread
constructor, a thread from the thread pool or a thread created by
System.ComponentModel.BackgroundWorker
.
The purpose of this API is to dispatch a call of the delegate instance on the UI thread. If the call to
Control.Invoke
or
Control.BeginInvoke
is done in UI thread, the delegate will be called immediately. As the invocation mechanism is redundant in this case, this can be avoided by checking the predicate property
Control.InvokeRequired
. If invocation mechanism is not required, regular call of control's method or property is preferred. This predicate is only needed for some generalization of some call which can be done from different threads: sometimes in UI thread, sometimes not. In many cases the developer knows for sure that the delegate will be called on from non-UI thread only; in this case
Control.InvokeRequired
is not needed, as invocation should be used anyway.
Now, UI libraries (both
System.Windows.Forms
and WPF) are designed in such a way that all calls to all UI controls and Application should never be done directly, but should dispatched to the UI thread. There is another interface to this functionality common for Forms and FPW, with highly extended functionality:
System.Windows.Threading.Dispatcher
, it also has
Invoke
and
BeginInvoke
methods, several overloads. The instance of
Dispatcher
can be obtained using the static property
System.Windows.Threading.Dispatcher.CurrentDispatcher
(this property either instantiates new instance or use previously created instance of
Dispatcher
).
Now,
Dispatcher
methods,
Control.Invoke
and
Control.BeginInvoke
use the same mechanism of dispatching a delegate to the UI thread: the delegate instance and instances of actual calling parameters are put to some queue, which is read by the WPF or
System.Windows.Forms
UI thread. In main UI cycle, this data is removed from the queue and used to make an actual call. Each thread instance has the invocation list; each element of invocation list encapsulates delegate entry point,
this
parameter used to access the instance of the declaring class of the method (if the method is non-static) and all instances of call parameters. All this data is used for the actual call.
Now we came to the difference between
Invoke
and
BeginInvoke
. For
Invoke
, return value obtained from the call is returned to caller of
Invoke
. It means that the thread synchronization is blocking for the calling non-UI thread.
In contrast,
BeginInvoke
returns immediately with the result of the type
System.IAsyncResult
, so this call itself in non-blocking. This invocation method should be used in most cases, especially when return result is not needed; a typical example: getting UI thread showing notification from non-UI thread status.
If return result from
BeginInvoke
is needed, the situation is pretty complex, as result is not ready immediately, so some kind of wait is needed anyway. It is not well documented in standard help documentation. Basically, there are three ways of obtaining the result of invocation later, one of them is calling blocking
EndInvoke
. You can find further details and recommendations here:
http://support.microsoft.com/kb/315582[
^].
There is a very popular misconception that the invocation mechanism can be used with any thread through
Dispacher
. This is not true. The
Dispatcher
really works for non-UI applications as well, but is
Invoke
or
BeginInvoke
is used, it does not do anything useful if there is no active UI thread! The call to those method is equivalent to regular call of the delegate on the same thread.
Is is possible to use the similar mechanism on any thread? No, but it can be done on specially written custom thread using a blocking queue, when the elements of the queue are delegate instances. A complete code with usage samples can be found in my Tips/Tricks article:
Simple Blocking Queue for Thread Communication and Inter-thread Invocation[
^]. If you look at the source code, it will give you a good idea on how UI thread invocation mechanism works.
—SA