Multithreading: introducing the asynchronous programming model
Today we’re going to keep looking at multithreading on the .NET framework and we’re going to start talking about the oldest async model you’ll find in the .NET framework: the APM (asynchronous programming model). You might be asking why you need an asynchronous programming model and why shouldn’t you use the threads or thread pool directly.
The APM is one of two parallel modes (we’ll leave the event based pattern for future posts) we’re going to look at and it can be seen as a pattern for letting operations execute in parallel and take care of all the internal details that go with these kind of operations (waiting, polling, etc). We all know the value of patterns, so I guess that’s enough for justifying its use. As I’ve said, the APM is the oldest async model and has been around since the release of .NET.
It relies on the use of the IAsyncResult interface and on the usage of a couple of begin and end methods on the form BeginActionName and EndActionName. The APM is the way to go when you’re building reusable libraries (you’ll typically use the event based pattern for UI components).
In theory, you can transform any synchronous operation in an asynchronous operation by adding a couple of methods. For instance, if you’ve got a synchronous method named Calculate and you want to change your API so that it supports asynchronous processing through the use of the APM pattern, then you need to start by adding two methods named BeginCalculate and EndCalculate.
The BeginCalculate method accepts the same number of parameters as the Calculate method + two new parameters:
- an AsyncCallback method, which will be invoked when the operation completes;
- an object state parameter, which allows you to pass state to the callback method.
This method always returns an instance of type IAsyncResult interface. The AsyncCallback delegate looks like this:
public delegate void AsyncCallback(IAsyncResult ar);
The EndCalculate method receives a single parameter, of type IAsyncResult. As we’ll see, there are several options for waiting for the async operation to complete. What you should keep in mind is that you should always call the EndCalculate method when to recover the result of the operation or to catch eventual exceptions that might have been through during the asynchronous operation.
If you don’t call the method,you’re probably swallowing exceptions and,even worst, you’re not cleaning up the internal structures used. Btw, and just to wrap up with the EndXXX method, it’s important to mention that it returns the same type as the synchronous method.
As I’ve said, most of the work necessary for making everything work, is encapsulated by the IAsyncResult implementation which is built during the BeginCalculare method. Since this is a really important interface, we’ll have to dedicate a complete post to it and that’s what we’ll do on the next post.
Keep tuned for more about multithreading.