Iv. Event-based asynchronous mode (design level)
The event-based C # asynchronous programming mode is a more advanced asynchronous programming mode than the iasyncresult mode, and is also used in more occasions. This asynchronous mode has the following advantages:
· Execute time-consuming tasks (such as downloading and Database Operations) in the background without interrupting your applications.
· Execute multiple operations at the same time, and a notification will be sent when each operation is completed (in the notification, you can tell which operation is completed ).
· Wait for the resources to become available, but do not stop ("Suspend") your application.
· Use familiar events and delegate models to communicate with pending asynchronous operations.
It can be used directly for relatively simple applications. the backgroundworker component added by NET 2.0 is easy to implement. For more complex asynchronous applications, You need to implement a class that complies with the event-based C # asynchronous programming mode. Before implementing the design of event-based asynchronous mode, you need to understand the implementation principle of event-based asynchronous mode. Event-based asynchronous mode requires the following three types of help.
Asyncoperation: Supports tracking the lifetime of asynchronous operations, including operation progress notifications and operation completion notifications, and ensures that client event handlers are called in the correct thread or context.
Public void post (sendorpostcallback D, object Arg );
Public void postoperationcompleted (sendorpostcallback D, object Arg );
Call the POST method in the asynchronous auxiliary code to report the progress and intermediate results to the user. If the asynchronous task is canceled or the asynchronous task is completed, call the postoperationcompleted method to end the tracking life cycle of asynchronous operations. After the postoperationcompleted method is called, The asyncoperation object becomes no longer available, and an exception occurs when you access the object again. There is a problem here:In this asynchronous mode, when the post function of asyncoperation is used to notify the progress, how can sendorpostcallback be executed on the UI thread?The following is a detailed analysis of this problem.
Asyncoperationmanager: This provides a convenient way to create asyncoperation objects. You can use the createoperation method to create multiple asyncoperation instances to track multiple asynchronous operations.
Windowsformssynchronizationcontext: This class inherits from the synchronizationcontext type and provides the synchronization context of the Windows Forms Application Model. This type is the core of event-based asynchronous mode communication. This type is the core of communication based on the asynchronous event mode because it solves theEnsure that the sendorpostcallback delegate is executed on the UI thread. How is it solved? See the implementation of the post method of asyncoperation type:
/// <Summary> /// implementation of the asyncoperation POST method /// </Summary> Public void post (sendorpostcallback D, object Arg) {This. verifynotcompleted (); this. verifydelegatenotnull (d); this. synccontext. post (D, ARG );}
The post method of the asyncoperation type directly calls the POST method of the synchronizationcontext type, and then the implementation of the post method is as follows:
/// <Summary> /// implementation of the post method of windowsformssynchronizationcontext type /// </Summary> Public override void post (sendorpostcallback D, object state) {If (this. controltosendto! = NULL) {This. controltosendto. begininvoke (D, new object [] {state}); // This ensures that sendorpostcallback is executed on the UI thread }}
Based on the above three types (asyncopertion, asyncoperationmanager, and synchronizationcontext), it is much easier to implement progress notifications and complete notifications in event-based asynchronous mode. The following uses an event-based Asynchronous model example to end this article.
Using system; using system. collections. generic; using system. text; using system. componentmodel; using system. collections. specialized; using system. threading; namespace test {/// <summary> /// progress notification proxy for Task 1 /// </Summary> /// <Param name = "sender"> </param> /// <Param name = "E"> </param> Public Delegate void work1progresschangedeventhandler (Object sender, work1progresschangedeventargs E); /// <summary> // enter the Task 1 Degree notification parameter /// </Summary> /// <Param name = "sender"> </param> /// <Param name = "E"> </param> public Delegate void work1completedeventhandler (Object sender, work1completedeventargs E); public class extends {private delegate void workereventhandler (INT maxnumber, asyncoperation asyncop); Private hybriddictionary userstatetolifetime = new hybriddictionary (); Public extends (){}# The event-based Asynchronous call of region dowork1 public void dowork1async (Object userstate, int maxnumber) {asyncoperation asyncop = asyncoperationmanager. createoperation (userstate); // userstatetolifetime may be accessed by multiple threads at the same time. Here, you need to lock and perform synchronization lock (userstatetolifetime. syncroot) {If (userstatetolifetime. contains (userstate) {Throw new argumentexception ("userstate parameter must be unique", "userstate");} userstatetolifetime [Use Rstate] = asyncop;} // start Task 1 asynchronously workereventhandler workerdelegate = new workereventhandler (dowork1); workerdelegate. begininvoke (maxnumber, asyncop, null, null);} private void dowork1 (INT maxnumber, asyncoperation asyncop) {exception E = NULL; // The task for judging the userstate is still being processed if (! Taskcanceled (asyncop. usersuppliedstate) {try {int n = 0; int percentage = 0; while (n <maxnumber &&! Taskcanceled (asyncop. usersuppliedstate) {thread. sleep (100); // simulate time-consuming operations percentage = (INT) (float) N/(float) maxnumber * 100); work1progresschangedeventargs progresschanageargs = new work1progresschangedeventargs (maxnumber, percentage, asyncop. usersuppliedstate); // The Progress of Task 1 is notified to asyncop. post (New sendorpostcallback (work1reportprogresscb), progresschanageargs); N ++ ;}} catch (exception ex) {e = ex ;}t His. work1complete (E, taskcanceled (asyncop. usersuppliedstate), asyncop);} private void work1complete (exception, bool canceled, asyncoperation asyncop) {If (! Canceled) {lock (userstatetolifetime. syncroot) {userstatetolifetime. remove (asyncop. usersuppliedstate) ;}} work1completedeventargs E = new work1completedeventargs (exception, canceled, asyncop. usersuppliedstate); // notifies you that the specified task has completed asyncop. postoperationcompleted (New sendorpostcallback (work1completecb), e); // call the postoperationcompleted method to end the lifetime of asynchronous operations. // An exception occurs when you call this method for a specific task and then call its corresponding asyncoperation object.} Private void work1reportprogresscb (object state) {e = state as finished; onwork1progresschanged (E);} private void work1completecb (object state) {work1completedeventargs E = state as work1completedeventargs; onwork1completed (e) ;}# region work1 progress notification and task completion event public event work1progresschangedeventhandler work1progresschanged; protected virtual v Oid onwork1progresschanged (work1progresschangedeventargs e) {work1progresschangedeventhandler temp = This. work1progresschanged; If (temp! = NULL) {temp (this, e) ;}} public event work1completedeventhandler work1completed; protected virtual void onwork1completed (work1completedeventargs e) {worker temp = This. work1completed; If (temp! = NULL) {temp (this, e );}} # endregion // <summary> // cancel the task execution of the specified userstate /// </Summary> /// <Param name = "userstate"> </Param> Public void cancelasync (Object userstate) {asyncoperation asyncop = userstatetolifetime [userstate] As asyncoperation; If (asyncop! = NULL) {lock (userstatetolifetime. syncroot) {userstatetolifetime. Remove (userstate) ;}}/// <summary> // determine whether the task of the specified userstate has been completed. Returned value: True is over; false has not ended /// </Summary> /// <Param name = "userstate"> </param> /// <returns> </returns> private bool taskcanceled (object userstate) {return (userstatetolifetime [userstate] = NULL) ;}} public class failed: progresschangedeventargs {private int totalwork = 1; Public work1progresschangedeventargs (INT totalwork, int progresspercentage, object userstate ): base (progresspercentage, userstate) {This. totalwork = totalwork;} // <summary> // total workload of work1 /// </Summary> Public int totalwork {get {return totalwork ;}}} public class work1completedeventargs: asynccompletedeventargs {public work1completedeventargs (exception E, bool canceled, object state): Base (E, canceled, state ){}}}