Keywords: Activity object
Reposted from: Yang Qin's blog http://www.cnblogs.com/felixYeou/
Section 1st understand activity objects
The use of activity objects in Symbian OS is undoubtedly the most basic, frequent, and important. What are activity objects?
When you learn a new thing, you will always compare this new thing with the thing you know to achieve quick learning. When I started to learn Symbian, I checked many Symbian books and many Symbian tutorials on the Internet all associated activity objects with multithreading. I always think of activity objects as a thread. However, after more in-depth contact, I found that it is not as I imagined.
Now, I want to assure you that the activity object has nothing to do with multithreading! Do not understand activity objects with the idea of multithreading!
The activity object can be understood as follows:
Many asynchronous functions are provided in Symbian OS. Most of these asynchronous functions are based on the "server-client" architecture. This is very different from the functions in Win32 API. For example:
In Win32, csocket: receive (Recv instead of wsarecv) is a synchronous function, and the thread is blocked at the receive until the socket receives the network stream.
Symbian OS also has a similar function, rsocket: receive, but this function is an asynchronous function, the thread will not block in the receive and will continue to execute.
How can we differentiate functions in Symbian from Synchronous functions and asynchronous functions? Simple: Check whether the function contains parameters of the trequeststatus type. If yes, the function is an asynchronous function. For example, the rsocket: receive function is prototype:
CPP Code Import_c void Recv (tdes8 & adesc, tuint flags, trequeststatus & AStatus)
The AStatus parameter is a status bit and the initial value is erequestpending (value: 1). It indicates whether the operation requested by the user has been completed. For example, if we call the asynchronous function rsocket: receive to request to receive network streams, the receive function will return directly. After the process of "receiving" a network stream is completed, the AStatus changes to eactive. Therefore, we only need to monitor whether the AStatus is not erequestpending and whether the "receiving" is complete.
We can use the following pseudo code to complete the above operations:
CPP Code <Br/> trequeststatus status (krequestpending); <br/> rsocket: receive (adesc, flags, status); <br/> (;;) <br/>{< br/> If (status! = Krequestpending) break; <br/>}< br/> // here we have completed synchronization similar to csocket: receive through rsocket: receive
We do not recommend that you use the above method for Symbian OS. We recommend that you use the asynchronous method instead of using this method to force synchronization. The active object is to help us do this. The activity object system helps us monitor the value of AStatus, As long as AStatus! = Erequestpending, he will notify us by event, telling us that "the socket has been received, you can get the data !", The activity object does this.
To sum up, there is an "activity scheduler" in the system. We create an "activity object ao1" and bind this object to an asynchronous function in a system, register the activity object to the "activity scheduler". The "activity scheduler" waits for the "completion" message returned by the asynchronous function. After receiving the completion message, the scheduler traverses the registered activity object. If the status is found! = Krequestpending: Find the "Active Object ao1" corresponding to the status, call the runl method, and notify us that the asynchronous function has been executed in Event Mode.
In the next section, I will introduce how to use activity objects.
Section 2nd use activity objects
In the previous section, we have roughly understood the basic concepts of activity objects. To use the activity object mechanism, we need to use activity objects, activity schedulers, and asynchronous functions. To use an asynchronous function, you must follow the procedure of application> activity Object> activity scheduler> asynchronous function. Next, we will start to use the activity objects.
1. Create an activity Scheduler
We know that the active scheduler serves as a bridge between an application and an asynchronous function. The application uses the active object to intercept the "completed" message returned by the asynchronous function through the active scheduler, and notify the application as an event.
Using carbide C ++ 1.3, the console program generated by the template wizard automatically generates code for creating the activity Scheduler for us:
CPP Code <Br/> cactivescheduler * scheduler = new (eleave) cactivescheduler (); <br/> cactivescheduler: Install (Scheduler); <br/> cactivescheduler: Install () after the method is called, the internal code will assign the scheduler pointer to the static pointer inside the cactivescheduler class, and the subsequent code will be able to conveniently use the static method of the cactivescheduler class, such:For example, CPP Code <Br/> import_c static void add (cactive * aactive); <br/> import_c static void start (); <br/> import_c static void stop ();
Add () method: add the activity object to the activity Scheduler for registration.
Start () method: Start the activity scheduler, which starts to wait cyclically for the notification message returned by the asynchronous function.
Stop () method: stop the activity Scheduler
2. Create activity objects
1. The created activity object must be derived from the cactive class, And the cactive class has prepared the istatus member variable for us:
CPP Code <Br/> Public: <br/> trequeststatus istatus; <br/> PRIVATE: <br/> tbool iactive;
Another member variable, iactive, plays an identity role and proves that the activity object has requested an asynchronous function, for example:
CPP Code <Br/> rtimer: After (istatus, 1000000); <br/> setactive ();
The setactive () method is used as the basic cactive method. In fact, iactive = etrue; is used to identify the activity object that has called the asynchronous function. Therefore, as long as an asynchronous function is called, the code that calls the asynchronous function should be followed by the code that calls the setactive () method.
2. Two pure virtual methods must be inherited:
CPP Code <Br/> virtual void docancel () = 0; <br/> virtual void runl () = 0;
Runl Method: After the activity scheduler receives the "finish" message returned by the asynchronous function, it traverses all the activity objects registered with it. If the iactive of the activity object is etrue and istatus! = Krequestpending: Call the runl method of the activity object and set iactive to efalse to prevent the activity object from being called in the next round-robin.
Here, the name "runl" may lead to ambiguity for many people. When I first came into contact, I always thought it was similar to the run method of the runnable interface in j21. In fact, it is more appropriate to change "runl" to "policyrequestcompletel" here.
Again, when an asynchronous function is called, The trequeststatus and status parameters are passed in reference mode, for example:
CPP Code Import_c void after (trequeststatus & AStatus, ttimeintervalmicroseconds32 aninterval );
So the asynchronous function can change the real parameter of status, that is, change the class member istatus of the activity object.
Docancel () method: The base class cactive has the cancel () method for canceling asynchronous functions. After cancel () is called, the activity object will pass docancel () the method notifies the application to cancel the method, such as deleting objects and revoking pointers. Note: To terminate an activity object in an application, use the cancel () method instead of the docancel () method.
3. constructors with priority for activity objects:
The prototype of the base class cactive constructor is as follows:
CPP Code <Br/> protected: <br/> import_c cactive (tint priority ority );
A priority enumeration value will be input here. The enumerated value is as follows:
CPP Code <Br/>/** <br/> defines standard priorities for active objects. <br/> */<br/> Enum tpriority <br/> {<br/>/** <br/> a low priority, useful for active Objects representing <br/> background processing. <br/> */<br/> epriorityidle =-100, </P> <p>/** <br/> A priority higher than epriorityidle but lower than eprioritystandard. <br/> */<br/> eprioritylow =-20, </P> <p>/** <br/> most active objects will have this priority. <br/> */<br/> eprioritystandard = 0, <br/>/** <br/> A priority higher than eprioritystandard; useful for active objects <br/> handling user input. <br/> */<br/> epriorityuserinput = 10, </P> <p>/** <br/> A priority higher than epriorityuserinput. <br/> */<br/> epriorityhigh = 20, <br/> };
When you call the cactivesched: add method to register an activity object, the activity scheduler sorts the activity objects according to their priorities and inserts or adds them to the activity object set. When multiple asynchronous function messages are returned at the same time (multiple istatus are not krequestpending at the same time ), when an activity object scheduler training set, it always finds the activity object with a higher priority and calls its runl method.
However, in general, eprioritystandard is passed in the constructor.
3. pseudocode of the Start method of the activity Scheduler
Through the above two analyses, we can simulate the cactivescheduler: Start method:
CPP Code <Br/> void cactivescheduler: Start () <br/>{< br/> (;;) <br/>{< br/> // suspend the thread until the asynchronous function message is returned <br/> // note: the active scheduler and application are not in the same thread, therefore, the application will not block <br/> User: waitforanyrequest (); // If the asynchronous function and the main program are in different threads, rthread: waitforanyrequest (); <br/> // when a message is returned, the thread will wake up <br/> // checks every activity object in the scheduler set in descending order of priority <br/> (; ;) <br/>{< br/> // call the first completed and iactive event handler function of the activity object = etrue <br/> If (activeobject-> isactive () & activeobject-> istatus! = Krequestpending) <br/> {<br/> // find an activity object that is ready to handle the event <br/> // reset the iactive status to indicate that it is no longer in the active status <br/> activeobject-> iactive = efalse; <br/> // call the event processing function of the activity object in the trap <br/> trapd (ERR, activeobject-> runl () <br/>; <br/> If (Err! = Kerrnone) <br/>{< br/> // call the runerror method of the activity object if an exception occurs. <br/> err = activeobject-> runerror (); <br/> If (Err! = Kerrnone) <br/>{< br/> error (ERR); <br/>}< br/> break; <br/>}< br/>
4. Examples of using activity objects
Click here to download the source code
In this example, a console program is started and the rtimer timer of the asynchronous service class is used to display the accumulated number on the screen every second. The effect is as follows:
V. Summary
In this section, we have a basic understanding of the working mechanism and workflow of the activity scheduler and activity objects. In the next section, we will go deep into the activity objects, understand its working principles and further deepen its understanding of the activity objects.
Vi. References
1. Symbian OS explained valid tive C ++ programming for smartphones
Section 3 how the activity object works.
In the previous section, we have learned how to create and use activity objects. You have a certain understanding of the creation and use of activity objects. In this section, I will go deep into the activity object mechanism, which is divided into two parts: "activity object Workflow" and "signal loss error", to analyze the working principle of the activity object.
I. workflow of activity targets
First, we use the sequence diagram to illustrate the process of creating and calling between applications, activity objects, activity schedulers, and asynchronous function servers:
The following describes how to use the code for each step (Click here to download the code:
1. Create and install the active scheduler:
CPP Code <Br/> cactivescheduler * scheduler = new (eleave) cactivescheduler (); <br/> cleanupstack: pushl (schedhl); <br/> cactivescheduler: Install (Scheduler );
If you have created an application based on the GUI application framework and the framework has already created and installed an active scheduler for us, we can directly use a series of methods of cactivescheduler.
2. Create activity objects
CPP Code Imyao = cmyactiveobject: newl (* console );
The cmyactiveobject class created here is the activity object inherited from the cactive class.
3. Add the activity object to the activity scheduler.
CPP Code <Br/> void cmyactiveobject: constructl () <br/>{< br/> .... <br/> cactivescheduler: add (this); // Add to scheduler <br/>}
As you can see, when an activity object is created through the "two-phase structure", its pointer has been added to the activity scheduler.
4. startl
Startl calls the asynchronous Function Method for the activity object requested by the application. You can rename this method as needed:
CPP Code <Br/> void cmyactiveobject: startl (ttimeintervalmicroseconds32 adelay) <br/>{< br/> cancel (); // cancel asynchronous function requests <br/> istatus = krequestpending; <br/> itimer. after (istatus, adelay); // call the asynchronous function here <br/> setactive (); // set the member variable iactive = etrue <br/>}
The startl method cannot be called again when the asynchronous function call is completed. Therefore, the cancel () method is called to cancel the asynchronous request at the entry point of the startl method, otherwise, the "Lost signal" error may occur.
5. istatus = krequestpending
In the startl method of the above Code, before calling an asynchronous function, you must first set istatus to krequestpending to enable the active scheduler to perform time-over-time matching.
6. Request asynchronous functions and send istatus
In the startl method, itimer. After (istatus, adelay); this line of code passes a reference to the member variable and calls the asynchronous function itimer. After.
7. setactive
Call the setactive method of the base class cactive to set the iactive to etrue in the method so that the active scheduler can match the time and duration.
8. Start the activity Scheduler
CPP Code <Br/> cactivescheduler: Start ();
10. Search for the corresponding activity object
We have analyzed and restored the pseudo code of the cactivescheduler: Start () method in the previous section. This code block traverses all the activity objects registered with the scheduler in another thread, check that the object's istatus is not krequestpending and the iactive is etrue. After the asynchronous function server completes the request, it will change the real parameter of istatus so that it is not equal to krequestpending, in addition, the iactive value of the activity object is changed to etrue immediately after the asynchronous function is returned, so the activity Scheduler only needs to judge istatus! = Krequestpending & iactive = etrue, you can know which activity object requested the asynchronous service has been completed.
9. waitforanyrequest () waits for the asynchronous function to return a notification. 11. requestcomplete () and changes the value of istatus.
When the asynchronous service has completed the requested work, it will use User: requestcomplete () to send a notification, the activity scheduler will use User: waitforanyrequest () or rthread :: waitforanyrequest () receives this notification, and then traverses the activity object that matches the conditions it is registered with (8th underlines ).
12. Call the runl Method
If the activity object corresponding to the asynchronous function is found, the runl method of the activity object is called, and the runl method runs in the trap macro. If the runl method throws an exception, the activity scheduler automatically calls the runerror method of the activity object. Therefore, you do not need to write exception capture code in runl in most cases.
After the runl method is called for an activity object, set the iactive value of the activity object to efalse so that the processed activity object can be skipped the next time the collection is traversed.
If the activity object corresponding to the asynchronous function is not found, the activity scheduler throws a "lost signal" exception.
13. cactivescheduler: Stop ()
Stop the event scheduler and stop monitoring signals returned by asynchronous functions.
Ii. Dedicated error of activity objects-"Lost signal"
From the above analysis, we know that the activity scheduler intercepts the messages returned by the asynchronous function, and then traverses the activity object set to find the corresponding activity object call. If not, it throws a "signal loss" exception. You can use either of the following methods to "cannot find the activity object:
The activity object is not registered to the activity scheduler at all: the cactivescheduler: add method is not called to register the activity object.
Unable to meet the istatus standard used by the activity scheduler to search for activity objects! = Krequestpending & iactive = etrue: After the asynchronous function is called, The setactive () method is not called to set the value of iactive to etrue; or the istatus is sent to two asynchronous functions at the same time, when the second asynchronous function returns, the iactive value of the current active object is efalse, And the Scheduler cannot find the corresponding activity object.
Iii. Summary
In this section, we learned the internal working principle of the activity object and gained a deeper understanding of the activity object processing mechanism. In the next section, we will learn how to synchronously call existing asynchronous functions.
4th synchronous call of asynchronous Functions
In the previous section, we have a deep understanding of the working principles and operating mechanisms of activity objects, activity schedulers, and asynchronous function servers. We are sure that you are familiar with the use of the mechanism and architecture of activity objects. But do you think it is troublesome to use Asynchronous functions? Do I have to use an active object to call an asynchronous function in asynchronous mode? This section will solve this problem: Synchronous use of asynchronous functions.
1. Use the cactiveschedulerwait class
In the previous article "Symbian programming Summary-ui-open JPEG/GIF/PNG images", we have seen how to use the cactiveschedulerwait class. I will introduce it in detail here.
Many beginners mix the cactiveschedit and cactiveschedulerwait classes at the beginning. cactivescheduler is the scheduler of the activity object, while cactiveschedulerwait can be simply understood as a scheduler of the current thread:
* When the cactiveschedulerwait: Start () method is called, the thread is blocked;
* When the cactiveschedulerwait: asyncstop () method is called, the request stops blocking the thread.
Therefore, without modifying the code of the original active object, simply add "cactiveschedulerwait: Start ()" after the asynchronous function call method ()", add "cactiveschedulerwait: ansycstop ()" to the beginning of the runl method of the activity object.
For the console application described in the previous tutorial, we can modify the following methods (the underline is the modification part:
Click here to download the source code
CPP Code <Br/> cactiveschedulerwait * iwait; </P> <p> void cmyactiveobject: constructl () <br/>{< br/> User: leaveiferror (itimer. createlocal (); // initialize timer <br/> cactiveschedmer: add (this); // Add to scheduler <br/> iwait = new (eleave) cactiveschedulerwait; <br/>}</P> <p> cmyactiveobject ::~ Cmyactiveobject () <br/>{< br/> cancel (); // cancel any request, if outstanding <br/> itimer. close (); // destroy the rtimer object </P> <p> // Delete instance variables if any <br/> If (iwait-> isstarted ()) <br/>{< br/> iwait-> asyncstop (); <br/>}< br/> Delete iwait; <br/> iwait = NULL; <br/>}</P> <p> void cmyactiveobject: startl (ttimeintervalmicroseconds32 adelay) <br/>{< br/> cancel (); // cancel any request, just to be sure <br/> itimer. after (istatus, adelay); // set for later <br/> setactive (); // tell scheduler a request is active <br/> iwait-> Start (); // <br/>}</P> <p> void cmyactiveobject: runl () <br/>{< br/> iwait-> asyncstop (); // <br/> tbuf <50> outputstr; <br/> outputstr. appendnum (icount); <br/> iconsole. write (outputstr); <br/> iconsole. write (_ L ("/N"); <br/> icount ++; <br/>}
Precautions for using cactiveschedulerwait:
1. cactiveschedulerwait must be used in conjunction with the activity object, and only the code described above can be used;
2. The start method and asyncstop method must appear in pairs;
3. Check whether cactiveschedulerwait is in the isstarted () status when the program exits. If yes, call the asyncstop method. Otherwise, the program cannot exit normally;
4. The cactivescheduler class has its own static pointer. All provided static methods call internal static pointers. The cactiveschedulerwait class does not have internal static pointers, and the method is not static. We must manage the global pointers of the cactiveschedulerwait class by ourselves. At this point, the program should be well designed.
Ii. Use the user: waitforrequest Method
If you do not want to use activity objects or cactiveschedulerwait that is difficult to manage, you can use the user: waitforrequest method. The following is a prototype of user: waitforrequest:
CPP Code Import_c static void waitforrequest (trequeststatus & AStatus );
This method will wait for the semaphore returned by the asynchronous function server and then match the AStatus parameter. If the received signal matches the AStatus parameter one by one, skip the blocking and enter the next line of code. Otherwise, the blocking thread continues until the signal corresponding to the AStatus is returned.
User: waitforrequest also has an overloaded method, which can monitor notifications of two signals:
CPP Code Import_c static void waitforrequest (trequeststatus & astatus1, trequeststatus & astatus2 );
With user: waitforrequest, It is very convenient to use Asynchronous functions. We do not need to create activity objects or create the member variable trequeststatus, you only need to declare partial trequeststatus and local asynchronous function classes. After the asynchronous function is called, Add User: waitforrequest (Status) to block the thread in user :: at waitforrequest, wait until the asynchronous function corresponding to status is processed completely.
CPP Code Local_c void dotestl () <br/>{< br/> rtimer timer; <br/> cleanupclosepushl (timer); <br/> User: leaveiferror (timer. createlocal (); </P> <p> trequeststatus status (krequestpending); </P> <p> // call the Asynchronous Method and pass status to <br/> timer. after (status, 1000000); </P> <p> // wait for the semaphore corresponding to status. Here User: is used :: the waitforrequest method simulates Asynchronous Method calls for synchronization <br/> User: waitforrequest (Status); </P> <p> cleanupstack: Pop (& timer ); <br/>}</P> <p> local_c void mainl () <br/>{< br/> tint n = 0; <br/> tbuf <10> STR; <br/> _ timeout (knewline, "/N "); </P> <p> forever <br/> {<br/> dotestl (); <br/> Str. num (n); <br/> N ++; </P> <p> console-> write (STR); <br/> console-> write (knewline ); <br/>}< br/>
Iii. Problems with using the user: waitforrequest Method
User: waitforrequest sometimes does not run normally, such as: cimagedecoder: Convert method:
CPP Code
Import_c virtual void convert (trequeststatus * arequeststatus, cfbsbitmap & adestination, cfbsbitmap & adestinationmask, tint aframenumber = 0 );
The last parameter must be eoptionalwaysthread, and user: waitforrequest can be executed normally. In my opinion, cimagedecoder :: if the eoptionalwaysthread parameter is not added to convert, it is implemented using a "long-term task" (which will be described in the next section. Therefore, the cimagedecoder: Convert method should be called as follows:
CPP Code Trequeststatus status (krequestpending); </P> <p> cimagedecoder * decoder = cimagedecoder: filenewl (IFS, afilename, kmimetype ); </P> <p> decoder-> convert (& status, abitmap, cimagedecoder: eoptionalwaysthread); </P> <p> User: waitforrequest (Status ); </P> <p> Delete decoder; <br/> decoder = NULL;
Iv. Summary
This article describes how to use Asynchronous functions synchronously. In fact, there is also an asynchronous function synchronization method in early Symbian programming, that is, after the asynchronous function call, use the cactivescheduler: Start () method to nest the activity scheduler. However, this method has been replaced by cactiveschedulerwait after Symbian 7.0 and will not be introduced here. In the next section, we will introduce the long-running task of the activity object ).