There are several ways that operations can take place asynchronously in .NET. Since you didn't post any specifics, I'll give an overview of the more common patterns:
AsyncWaitHandle
Often you'll find (especially in the .NET framework classes) pairs of methods named with Begin
and End
(i.e. something like BeginReceive
and EndReceive
).
Calling the begin function returns an AsyncWaitHandle
object, which can be used to synchronize threads like a regular WaitHandle
(by calling WaitOne
or passing it into the static WaitHandle.WaitAny
or WaitHandle.WaitAll
functions), then is passed into the corresponding "end" function to obtain the return value of the function (or, if one occurred, throw the exception that was encountered).
If you use the simple .NET facility for calling a method asynchronously (creating a delegate for the function and calling BeginInvoke
and EndInvoke
), then this is the approach you'll need to use. However, most API's that have built-in support for asynchronous operations will handle the actual asynchronous calling part for you, leaving you with properly named BeginXXX
and EndXXX
functions, rather than forcing you to create a delegate yourself.
Sample using the WaitHandle
:
IAsyncResult result = object.BeginOperation(args);
result.AsyncWaitHandle.WaitOne();
// that will cause the current thread to block until
// the operation completes. Obviously this isn't
// exactly how you'd ordinarily use an async method
// (since you're essentially forcing it to be
// synchronous this way)
returnValue = object.EndOperation(result);
Often async methods are coupled with events, as shown below.
Events
Sometimes a method call that completes asynchronously will raise an event upon its completion. This is also sometimes used in combination with the AsyncWaitHandle
approach to deliver the notification that the process has completed. For example, the MSMQ libraries have a BeginReceive
and EndReceieve
function on the queue object, as well as a ReceieveCompleted
event. When the event fires, it indicates that EndReceive
can then be called, passing in the AsyncWaitHandle
object returned from the call to BeginReceive
. to get the actual message that was received.
Either way, you attach to the event and use it as you would any other event.
Sample using AsyncWaitHandle
and events:
(somewhere in the code)
object.OperationComplete += object_OperationComplete;
(elsewhere)
IAsyncResult result = object.BeginOperation(args);
// at this point, you can either wait for the event
// to fire, or use the WaitHandle approach as shown
// in the previous example
...
void objectOperationComplete(object sender, AsyncOperationEventArgs e)
{
returnValue = object.EndOperation(e.AsyncResult);
}
These generally work in a variety of ways...you can hold on to the IAsyncResult
returned from the Begin operation yourself, but most libraries will pass that IAsyncResult
object as a property on their particular EventArgs
class.
It's also common to find the return value being present as a property on the EventArgs
class. While using this value is fine, if the Begin operation returned an IAsyncResult
, it's always a good idea to call the corresponding End function, even if the data you need is in the EventArgs
. The End function is usually the way that exceptions are caught, as well.
Callbacks
A callback (in .NET) is a delegate that is supplied to the asynchronous function. Callbacks are used in more than just asynchronous functions, but in this context they're generally a delegate that you supply when calling the function that it will call when it completes.
Callbacks are similar to events (in that they're both delegate-based), though there is more of a one-to-one correlation between the method calls and the callbacks supplied.
Example using a callback:
object.BeginOperation(args, OperationComplete);
...
void OperationComplete(SomeObject results)
{
...
}