Ziff-Davis Enterprise 
DevSource: Microsoft Developer Resource
Add OnsArchitectureLanguagesTechniquesUsing VSForums
 
Home arrow Using VS arrow Page 3 - Why Asynchronous Delegates Are Your Friend
Why Asynchronous Delegates Are Your Friend
By Jon Shemitz

Rate This Article:
Add This Article To:
Why Asynchronous Delegates Are Your Friend - ' Polling for Completion '
( Page 3 of 4 )

A delegate's BeginInvoke method has the same parameters as the delegate's Invoke method. This makes asynchronous execution the easy way to pass any number of parameters to a thread procedure.

(A delegate's BeginInvoke method also has two extra parameters that are used for an optional callback when the method terminates; I cover these required parameters in the Callback on completion section, below, but it's always perfectly safe to just pass null to each.)

ADVERTISEMENT

Every call to BeginInvoke, no matter which delegate you're invoking, returns an IAsynchResult that you must save and pass to the same delegate's EndInvoke method.

The EndInvoke method takes a single IAsynchResult parameter; waits for the call to complete; and returns the delegate result, if any. Note that EndInvoke does not return an object that you have to cast to the right type. Rather, EndInvoke has the same result type as the delegate itself: a delegate that 'returns' void has an EndInvoke method that 'returns' void; a delegate that returns a string has an EndInvoke method that returns a string; and so on.

There are several different ways to detect that an asynchronous call has completed, but you must pass the IAsyncResult that you get from ThisDelegate.BeginInvoke to ThisDelegate.EndInvoke. Yes, even if you already know the delegate has returned, and even if EndInvoke does not return a result.

Thus, the simplest asynchronous scenario is something like

IAsynchResult Asynch =
  ReadFileDelegate.BeginInvoke(Filename, null, null);
//
// Do as much as you can until you need
// the file contents: EndInvoke() blocks.
//
string FileContents = ReadFileDelegate.EndInvoke(Asynch);

Calling EndInvoke like this is not unlike calling Join on a thread: you don't need to know the current state of the operation, you just block until it's completed.

Asynchronous execution of delegates in a thread pool thread is not the same thing as sending a control a message asking it to execute a delegate in the control's thread! A (System.Windows.Forms) Control has a BeginInvoke method that takes a delegate, and an EndInvoke method that takes the IAsyncResult that BeginInvoke returned. These Control methods act differently than the delegate's own BeginInvoke and EndInvoke methods. The Control methods don't take callback parameters, and it is safe to not EndInvoke an IAsyncResult that you get from a Control.BeginInvoke call.

Polling for Completion

It's not always a good idea to block the application's main thread. It's okay in a command line utility that simply runs to completion with no user intervention, and it's okay in a web server where each incoming request runs in its own thread, but it's generally not okay in a GUI app, where blocking the main thread means that the app is not responding to mouse clicks and key presses.

If you initiate a lengthy asynchronous call from the main GUI thread, you might poll the IAsyncResult.IsCompleted property and call Application.DoEvents until the delegate returns:

IAsynchResult Asynch = ReadBigFileDelegate.BeginInvoke(Filename, null, null);
//
// Do something while waiting for file IO
//
while (! Asynch.IsCompleted) // we need the file contents now
  Application.DoEvents(); // handle events until delegate returns 
string FileContents = ReadBigFileDelegate.EndInvoke(Asynch);

A better design is usually for the ReadBigFileDelegate to run to completion, then use Control.BeginInvoke to have the GUI thread run a delegate that will do ReadBigFileDelegate. EndInvoke and display the fetched data.

Of course, while file IO is slow, it's not all that slow, and you can usually get away with reading a small (one or two kilobyte) file during an event handler. As a rule of thumb, if you can do something synchronously without impacting GUI responsiveness, the asynchronous version can certainly block on EndInvoke without impacting GUI responsiveness.

Waiting for Completion

If the asynchronous delegate has any side effects, other threads may want to wait for it to complete before doing anything that depends on those side effects. These threads can use WaitHandle methods like the IAsyncResult.AsyncWaitHandle.WaitOne instance method or the static WaitHandle methods WaitAll and WaitAny to wait until the IAsyncResult.AsyncWaitHandle event is signaled.

While you can call BeginInvoke in one thread and call EndInvoke in a different thread, this still allows only one thread to wait for the delegate. The AsyncWaitHandle property returns a ManualResetEvent that blocks all waiting threads until the event is signaled, and then lets all threads through after the event is signaled. That is, the AsyncWaitHandle property allows any number of threads to wait for the delegate. (However, you should be sure to only call EndInvoke once.)



 
 
>>> More Using VS Articles          >>> More By Jon Shemitz
 



DevSource video
Devsource Video Series
Manipulating Society through Technology
Jeremy Bailenson, Director of the Virtual Human Interaction Lab at Stanford University, talks about virtual reality, avatars, Moore's law, how real world behaviors influence online reality, and societal manipulation through technology!
>> Play video
>> Read article
>> See all videos
DevLife Blog

Julia explores the Robotics Studio! (It's for more than you think.)

MSDev Blog

Messages for Bill Gates!

Make it Work
.NET makes runtime type checking a breeze. See what Peter has to say about it in this week's tips!
News
Microsoft Counts on App Support for Vista
Microsoft has taken pains to demonstrate that Windows Vista will have ample application support.
DevSource RSS FEEDS
XML Want an easy way to keep up with breaking tech news? And the Get DevSource headlines delivered to your desktop with RSS.