Multithreading: introducing the event based asynchronous pattern
In the last posts we’ve looked at several details associated with the use of the APM pattern. Today we’re going to start looking at the second pattern for doing asynchronous work: the event based asynchronous pattern.
This pattern was introduced with .NET 2.0 and it targets components that are going to be used in GUIs. In other words, if you’re building components that are going to be used by developers that build GUIs, then you should prefer this pattern instead of the APM.
To implement this pattern, a class needs to:
- have a method with the name XXXAsync, where XXX is the name of the synchronous method;
- the XXXAsync method receives the same parameters that are expected by the synchronous version plus an optional object parameter (used to pass extra state that should be consumed later);
- expose an event with the name XXXCompleted, which should be fired when the asynchronous task completes;
- the EventArgs type of that event should be an AsyncCompletedEventArgs derived class;
- expose a CancelAsync method (which might optionally receive an object parameter) that is responsible for cancelling the async operation;
- optionally expose a ProgressChanged event (of type ProgressChangedEventHandler), that can be consumed for getting info on the progress of the operation.
Unlike the APM, the XXXAsync method that starts the asynchronous task does not return an IAsyncResult instance (in fact, it always returns nothing, ie, void). This means that the only option available for “waiting” for the completion of the task is handling the event.
Notice that a class that has one XXXAsync method might support the execution of several concurrent tasks. In those cases, you do need to have the extra state parameter I’ve mentioned above because it is used for distinguishing between the multiple executing operations (if you don’t want to support multiple execution,then you don’t need that extra parameter).
If you’re building GUIs (ex.: windows forms apps),you don’t really care much about the flexibility of the APM. In fact, in these scenarios, the event based pattern is your best option. Why? Simple: because the method that handles the event will be fired on the GUI thread (which, btw, is required for interacting with the controls – ie, whenever you need to update a control, you need to do it from the GUI thread).
Another great feature of the event based pattern is that it offers first class cancelation support (which does not happen with the APM). As we’ve seen, a class that implements this pattern needs to expose a CancelAsync method, which the consuming developer can use for cancelling the current asynchronous operation. Notice that when you support multiple concurrent executions, you need to pass the state parameter to this method so that the class knows which operation should be cancelled.
Reporting on progress is another great feature which is very important for GUIs (generally, giving feedback about the status of the current operation is important for this kind of apps). As we’ve seen, a component that implements this pattern might decide to support this feature by exposing a ProgressChanged event. Notice that if the class exposes several XXXAsync method, then you should expose several events named XXXProgressChanged.
And I guess this sums it up. More about this pattern and multithreading on the next posts. Keep tuned.