Sie sind auf Seite 1von 8

The Microsoft .NET Framework makes it easy to call functions asynchronously.

Calling
functions asynchronously causes the system to execute them in the background on a secondary
thread while the calling function continues to do other work. In a typical (synchronous) function
call, the function is executed right away on the same thread that made the call. The calling
function waits for the call to complete and receives the results of the call before continuing. By
contrast, when you make an asynchronous call, you retrieve the results of the asynchronous call
later. This article demonstrates how to do this by using Visual C#.

Requirements
The following list outlines the recommended hardware, software, network infrastructure, and
service packs that are required:

Microsoft Windows 2000 or Microsoft Windows XP or Microsoft Windows Server 2003

Visual Studio .NET or Visual Studio 2005

This article assumes that you are familiar with the following topics:

Calling methods in Visual C#

How to use delegates

How To Make Asynchronous Calls


Asynchronous calls are made by using delegates. A delegate is an object that wraps a function.
Delegates provide a synchronous function and also provide methods for calling the wrapped
function asynchronously. Those methods are BeginInvoke() and EndInvoke(). The parameter
lists of these methods vary depending on the signature of the function that the delegate wraps.
Note that the Visual Studio .NET IntelliSense feature does not display BeginInvoke() and
EndInvoke(), so you do not see them appear in the function lists as you type.
BeginInvoke() is used to initiate the asynchronous call. It has the same parameters as the
wrapped function, plus two additional parameters that will be described later in this article.
BeginInvoke() returns immediately and does not wait for the asynchronous call to complete.
BeginInvoke() returns an IAsyncResult object.
The EndInvoke() function is used to retrieve the results of the asynchronous call. It can be
called anytime after BeginInvoke(). If the asynchronous call has not completed yet,
EndInvoke() blocks until it completes. The parameters of the EndInvoke() function includes the
out and ref parameters that the wrapped function has, plus the IAsyncResult object that is
returned by BeginInvoke().

The following is an example of a delegate and its BeginInvoke() and EndInvoke() methods:
// The following delegate
delegate string MethodDelegate(int iCallTime, out int iExecThread)

// will have the following BeginInvoke() and EndInvoke methods:


IAsyncResult MethodDelegate.BeginInvoke(int iCallTime, out int iExecThread,
AsyncCallback cb, object AsyncState);
string MethodDelegate.EndInvoke (out int iExecThread, IAsyncResult ar) ;

There are four common ways to use BeginInvoke() and EndInvoke() to make asynchronous
calls. After you call BeginInvoke(), you can:

Optionally do some other work and then use EndInvoke().

Obtain a WaitHandle that is provided by the IAsyncResult object, use its WaitOne
method to block until the WaitHandle is signaled, and then call EndInvoke().

Poll the IAsyncResult object to determine when the asynchronous call has completed,
and then call EndInvoke().

Have the system call a callback function that you specify. This callback function calls
EndInvoke() and processes the results of the asynchronous call when it completes.

The following code samples demonstrate these call patterns and contrast them with making a
synchronous call by using the following function:
string LongRunningMethod (int iCallTime, out int iExecThread)
{
Thread.Sleep (iCallTime) ;
iExecThread = AppDomain.GetCurrentThreadId ();
return "MyCallTime was " + iCallTime.ToString() ;
}

LongRunningMethod() simulates a function that runs for long time by sleeping. It returns the
sleep time and the ID of the thread that executes it. If you call it asynchronously, you find that
the thread ID of the executing thread is different from that of the calling thread.
The first step is to define the delegate that wraps the function:

delegate string MethodDelegate(int iCallTime, out int iExecThread)

Sample 1: Calling A Method Synchronously


This sample demonstrates how to call LongRunningMethod() synchronously by using a
MethodDelegate delegate. The other samples contrast this by making calls asynchronously.
1. Start Microsoft Visual Studio .NET or Microsoft Visual Studio 2005.

2. Create a new Visual C# Console Application project named AsyncDemo.


3. Add a class named AsyncDemo that is defined as follows to the project in a new .cs file:
4. using System;
5. using System.Threading ;
6. using System.Windows.Forms ;
7.
8. public class AsyncDemo
9. {
10.
string LongRunningMethod (int iCallTime, out int iExecThread)
11.
{
12.
Thread.Sleep (iCallTime) ;
13.
iExecThread = AppDomain.GetCurrentThreadId ();
14.
return "MyCallTime was " + iCallTime.ToString() ;
15.
}
16.
17.
delegate string MethodDelegate(int iCallTime, out int
iExecThread) ;
18.
19.
public void DemoSyncCall()
20.
{
21.
string s ;
22.
int iExecThread;
23.
24.
// Create an instance of a delegate that wraps
LongRunningMethod.
25.
MethodDelegate dlgt = new MethodDelegate
(this.LongRunningMethod) ;
26.
27.
// Call LongRunningMethod using the delegate.
28.
s = dlgt(3000, out iExecThread);
29.
30.
MessageBox.Show (string.Format ("The delegate call
returned the string:
\"{0}\",
31.
and the thread ID {1}", s,
iExecThread.ToString() ) );
32.
}
33. }

Later, this class demonstrates how to make asynchronous calls. Initially, however, it only
contains the DemoSyncCall() method, which demonstrates how to call the delegate
synchronously.
34. Add the following code in the body of the Main function that Visual Studio automatically
creates in your project:
35. static void Main(string[] args)
36. {
37.
AsyncDemo ad = new AsyncDemo () ;
38.
ad.DemoSyncCall() ;
39. }

40. Press CTRL+F5 to run your application.

Sample 2: Calling A Method Asynchronously by Using the EndInvoke() Call


Pattern
In this section, the sample invokes the same method asynchronously. The call pattern that is used
is to call BeginInvoke, do some work on the main thread, and then call EndInvoke(). Note that
EndInvoke() does not return until the asynchronous call has completed. This call pattern is
useful when you want to have the calling thread do work at the same time that the asynchronous
call is executing. Having work occur at the same time can improve the performance of many
applications. Common tasks to run asynchronously in this way are file or network operations.
1. Add a method named DemoEndInvoke() to the AsyncDemo class. The
DemoEndInvoke function demonstrates how to call the delegate asynchronously.
2. public void DemoEndInvoke()
3. {
4.
MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
5.
string s ;
6.
int iExecThread;
7.
8.
// Initiate the asynchronous call.
9.
IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, null, null);
10.
11.
// Do some useful work here. This would be work you want to
have
12.
// run at the same time as the asynchronous call.
13.
14.
// Retrieve the results of the asynchronous call.
15.
s = dlgt.EndInvoke (out iExecThread, ar) ;
16.
17.
MessageBox.Show (string.Format ("The delegate call returned
the string:
\"{0}\",
18.
and the number {1}", s,
iExecThread.ToString() ) );
19. }

20. Edit the source code for Main so that it contains the following code:
21. static void Main(string[] args)
22. {
23.
AsyncDemo ad = new AsyncDemo () ;
24.
ad.DemoEndInvoke() ;
25. }

26. Press CTRL+F5 to run your application.

Sample 3: Calling A Method Asynchronously And Using A WaitHandle To Wait


For The Call To Complete

In this section, the sample calls the method asynchronously and waits for a WaitHandle before it
calls EndInvoke(). The IAsyncResult that is returned by BeginInvoke() has an
AsyncWaitHandle property. This property returns a WaitHandle that is signaled when the
asynchronous call completes. Waiting on a WaitHandle is a common thread synchronization
technique. The calling thread waits on the WaitHandle by using the WaitOne() method of the
WaitHandle. WaitOne() blocks until the WaitHandle is signaled. When WaitOne() returns,
you can do some additional work before you call EndInvoke(). As in the previous sample, this
technique is useful for executing file or network operations that would otherwise block the
calling main thread.
1. Add a function named DemoWaitHandle() to the AsyncDemo class. The
DemoWaitHandle() function demonstrates how to call the delegate asynchronously.
2. public void DemoWaitHandle ()
3. {
4.
string s ;
5.
int iExecThread;
6.
7.
MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
8.
9.
// Initiate the asynchronous call.
10.
IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread,
null, null);
11.
12.
// Do some useful work here. This would be work you want to
have
13.
// run at the same time as the asynchronous call.
14.
15.
// Wait for the WaitHandle to become signaled.
16.
ar.AsyncWaitHandle.WaitOne() ;
17.
18.
// Get the results of the asynchronous call.
19.
s = dlgt.EndInvoke (out iExecThread, ar) ;
20.
21.
MessageBox.Show (string.Format ("The delegate call returned
the string:
\"{0}\",
22.
and the number {1}", s,
iExecThread.ToString() ) );
23. }

24. Edit the source code for Main so that it contains the following code:
25. static void Main(string[] args)
26. {
27.
AsyncDemo ad = new AsyncDemo () ;
28.
ad.DemoWaitHandle () ;
29. }

30. Press CTRL+F5 to run your application.

Sample 4: Calling A Method Asynchronously by Using the Polling Call Pattern


In this section, the sample polls the IAsyncResult object to find out when the asynchronous call
has completed. The IAsyncResult object that is returned by BeginInvoke() has an IsCompleted
property that returns True after the asynchronous call completes. You can then call
EndInvoke(). This call pattern is useful if your application does ongoing work that you do not
want to have blocked by a long-running function call. A Microsoft Windows application is an
example of this. The main thread of the Windows application can continue to handle user input
while an asynchronous call executes. It can periodically check IsCompleted to see if the call has
completed. It calls EndInvoke when IsCompleted returns True. Because EndInvoke() blocks
until the asynchronous operation is complete, the application does not call it until it knows that
the operation is complete.
1. Add a function named DemoPolling() to the AsyncDemo class. The DemoPolling()
function demonstrates how to call the delegate asynchronously and use polling to see if
the process is complete.
2. public void DemoPolling()
3. {
4.
MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
5.
string s ;
6.
int iExecThread;
7.
8.
// Initiate the asynchronous call.
9.
IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, null, null);
10.
11.
// Poll IAsyncResult.IsCompleted
12.
while(ar.IsCompleted == false)
13.
{
14.
Thread.Sleep (10) ; // pretend to so some useful work
15.
}
16.
s = dlgt.EndInvoke (out iExecThread, ar) ;
17.
18.
MessageBox.Show (string.Format ("The delegate call returned
the string:
\"{0}\",
19.
and the number {1}", s,
iExecThread.ToString() ) );
20. }
21.

22. Edit the source code for Main. Replace the content of the function with the following
code:
23. static void Main(string[] args)
24. {
25.
AsyncDemo ad = new AsyncDemo () ;
26.
ad.DemoPolling () ;
27. }

28. Press CTRL+F5 to run your application.

Sample 5: Executing a Callback When an Asynchronous Method Completes


In this section, the sample provides a callback delegate to the BeginInvoke() function that the
system executes when the asynchronous call completes. The callback calls EndInvoke() and
processes the results of the asynchronous call. This call pattern is useful if the thread that initiates
the asynchronous call does not need to process the results of the call. The system invokes the
callback on a thread other than the initiating thread when the asynchronous call completes.
To use this call pattern, you must pass a delegate of type AsyncCallback as the second-to-last
parameter of the BeginInvoke() function. BeginInvoke() also has a final parameter of type
object into which you can pass any object. This object is available to your callback function
when it is invoked. One important use for this parameter is to pass the delegate that is used to
initiate the call. The callback function can then use the EndInvoke() function of that delegate to
complete the call. This call pattern is demonstrated below.
1. Add a two methods named DemoCallback() and MyAsyncCallback() to the
AsyncDemo class. The DemoCallback() method demonstrates how to call the delegate
asynchronously. It uses a delegate to wrap the MyAsyncCallback() method, which the
system calls when the asynchronous operation completes. MyAsyncCallback() calls
EndInvoke().
2. public void DemoCallback()
3. {
4.
MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
5.
string s ;
6.
int iExecThread;
7.
8.
// Create the callback delegate.
9.
AsyncCallback cb = new AsyncCallback(MyAsyncCallback);
10.
11.
// Initiate the Asynchronous call passing in the callback
delegate
12.
// and the delegate object used to initiate the call.
13.
IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, cb,
dlgt);
14. }
15.
16. public void MyAsyncCallback(IAsyncResult ar)
17. {
18.
string s ;
19.
int iExecThread ;
20.
21.
// Because you passed your original delegate in the asyncState
parameter
22.
// of the Begin call, you can get it back here to complete the
call.
23.
MethodDelegate dlgt = (MethodDelegate) ar.AsyncState;
24.
25.
// Complete the call.

26.
27.
28.

s = dlgt.EndInvoke (out iExecThread, ar) ;

MessageBox.Show (string.Format ("The delegate call returned


the string:
\"{0}\",
29.
and the number {1}", s,
iExecThread.ToString() ) );
30. }
31.

32. Edit the source code for Main. Replace the content of the function with the following
code:
33. static void Main(string[] args)
34. {
35.
AsyncDemo ad = new AsyncDemo () ;
36.
ad.DemoCallback() ;
37. }

Das könnte Ihnen auch gefallen