Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

.NET

Control Implementation of ISynchronizeInvoke


.NET_template

Richard provides details on passing update information from worker threads to the user interface

In the last two newsletters, I have described how to handle the situation of invoking a lengthy routine on the UI thread. In essence, if the routine can be divided into short sections, you can call Application.DoEvents to ensure that the user interface is updated regularly. If this cannot be achieved, then you can perform the action on another thread; however, you must ensure that if the worker thread needs to update the user interface, it does this on the UI thread by passing a delegate to the update code to ISynchronizeInvoke.Invoke.

In fact, you have two choices of how to invoke a method—ISynchronizeInvoke has three methods, Invoke for “synchronous” invocation, and BeginInvoke and EndInvoke for “asynchronous” invocation. I use quote marks because whichever invocation method you use, the target method will be invoked on another thread for the default implementation for Control. (Clearly, if you write your own implementation of IsynchronizeInvoke, it is up to you to decide what “synchronous” and “asynchronous” invocation means.) The default implementation for Control is almost the same for both types of invocation. The first thing it does is obtain the “marshaling control”; this is the parent of all controls and is typically the form. MarshaledInvoke is called on the marshalling control passing the control that calls the method, the delegate, and its parameters. The final parameter of MarshaledInvoke is a flag that indicates whether it was called in response to Invoke or BeginInvoke. This is one difference between the two types of invocation, the other difference is that the return value of MarshaledInvoke for “synchronous” invocation is whatever value returned from the delegate. If BeginInvoke was called, the return value of MarshaledInvoke is an IAsyncResult on an asynchronous call object.

I will just give a basic explanation of how MarshaledInvoke works. First, the code obtains the thread ID of the thread that created the marshalling control by calling the Win32 GetWindowThreadProcessId function and compares this value with the thread ID of the current thread. If the two are the same, then no marshalling is required, and this means that the invocation can be performed on the current thread. If the call is “asynchronous” (through BeginInvoke) or if the calling thread is not the UI thread, then the delegate method must be invoked on the UI thread. The way that this is performed is by creating an instance of a “job” object of the type Control.ThreadMethodEntry, which is used to hold information about the method that will be invoked and its parameters. This class implements IAsyncResult, so it is used as the async call object that is returned by BeginInvoke.

The marshalling control will have a job queue, and once it is initialized, the job object is added to this queue. This queue can be accessed by multiple threads, so all access is controlled by synchronization through the Monitor class. Once the object is queued, the executing thread must be informed, and there are two ways that this can happen. If the invoking thread is not the UI thread, then the UI thread is informed by posting a Windows message with the Win32 PostMessage function. A window’s message queue will always be pumped on the thread that created it, so PostMessage will be handled by the UI thread. The message that is posted is a custom message called "WindowsForms11_ThreadCallbackMessage" for Version 1.1. This is handled by the default message handler in Control (WndProc) by calling the InvokeMarshaledCallbacks method, which loops until the job queue is empty. In each loop, it extracts a job object from the queue and invokes it according to the type of delegate in the job object.

The purpose of posting a message and handling the message is to ensure that the UI thread calls InvokeMarshaledCallbacks; if the invoking thread is the UI thread (and the invocation is “synchronous”), then MarshaledInvoke calls InvokeMarshaledCallbacks directly, without posting the message.

There is one further issue that I need to cover. MarshaledInvoke, called by the invoking thread, creates a CompressedStack object and places this into the ThreadMethodEntry job object. Then when the job object is dequeued by InvokeMarshaledCallbacks, the current thread is initialized with the compressed stack object. So what’s happening here? Well, the thread object contains much security information and is vital in the way that code access security works. There is a possible security breach here because when InvokeMarshaledCallbacks is called on the UI thread, it invokes a delegate that has been initialized on a different thread that may have different permissions. The CompressedStack object contains this security information, so it ensures that when the delegate is invoked on the UI thread, this thread is initialized with the appropriate code access security settings.


Richard Grimes speaks at conferences and writes extensively on .NET, COM, and COM+. He is the author of Developing Applications with Visual Studio .NET (Addison-Wesley, 2002). If you have comments about this topic, Richard can be reached at [email protected].



Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.