Concepts with Symbian OS (779878), страница 19
Текст из файла (страница 19)
Ideas of forking execution and joiningthreads together still exist for threads, because they are truly parallelentities. However, working with threads is much easier.Again consider Linux, so that we can compare it to the examplesabove. The following code contains a simple program to create and jointhreads of execution in a program.PROGRAMMING WITH PROCESSES83#include <synch.h>#include <thread.h>#include <unistd.h>void *child (void* args){printf("This is the child!\n");sleep(60);}void main(){thread_t yarn;thr_setconcurrency(2);thr_create(NULL, NULL, child, NULL, 0, &yarn);printf("This is the parent!\n");thr_join(yarn, &yarn, NULL);}Notice that each thread of execution is implemented by its ownfunction and concurrent threads are defined by function definitions.
Thecode produces a child that prints a message and terminates, becauseits definition terminates. The parent creates the thread through a call tothr_create(). The parent waits to join its execution thread with thechild’s by calling thr_join(). This call blocks until the child specifiedby the yarn descriptor terminates.Threads help to mitigate the difficulties found in the conventionalprocess model. Thread creation is easy and lightweight; thread contextswitching happens within a PCB. The operating system still has to keeptrack of threads, but bookkeeping requires less data. In addition, threadsallow sharing of all resources of the parent.The quicksort algorithm lends itself easily to a thread-based implementation, because recursive function calls can be replaced by threadcreation.
Like functions, threads share memory and the quicksort algorithm marks off portions of the same data array for each function or threadto work on. Joining the pieces back together is irrelevant, because eachthread worked on a portion of the same array.Programming in Symbian OSSymbian OS supports processes, threads and active objects, the specialcase of threads focused on external events. Symbian OS supports standard84PROCESSES AND THREADSand conventional interfaces, which allow processes and threads to beused in much the same way as on other systems such as Linux. SymbianOS supports the concepts of forking and joining processes, but does notclone a PCB when forking (it implements a ‘fresh’ executable image, notduplicated from the parent).
There are a few other differences, but theydo not affect the global concepts of process creation. Symbian OS alsosupports the POSIX thread manipulation APIs.Active objects are unique to Symbian OS. Recall that active objectsare Symbian OS threads that multitask cooperatively, that is, they aredesigned to facilitate asynchronous requests that wait for external events,usually tied to device I/O.
The keys to using an active object are thateach active object must release control to the operating system when it isready to wait for an external event and that each active object must keeptrack of its internal state, because execution is restarted at the same placeevery time it restarts.In Symbian OS programming, active objects are derived from theCActive class, which provides access to a CActiveScheduler object.An active object must implement at least two functions:void RunL()void DoCancel()The RunL() function is the heart of an active-object implementation.Upon construction, the active object creates and initializes anything itneeds. To inform the operating system that an asynchronous request hasbeen submitted (that the active object must wait for), the active objectcalls the function SetActive().
This suspends the active object thread,turning control of the asynchronous operation over to a scheduler. Whenthis operation completes and generates an event the active object hasregistered for, the scheduler calls the RunL() function for the activeobject.The DoCancel() function must be implemented to cancel the actionsimplemented by the active object. On receiving a request to cancel theoperations for an active object, the system first checks whether there isan outstanding request for this object, then calls DoCancel().There must be a way to start the active object. This should be a functionthat initializes the active object and executes the first asynchronousrequest.
This function then passes control to the scheduler by callingSetActive().PROGRAMMING WITH PROCESSES85Consider an example that sends an object over the serial port of aSymbian OS device. We could start this sending process by calling thefollowing function:void TodoXferSerialAO::SendItem(CAgnEntry *aEntry){iEntry = aEntry;CParaFormatLayer *iParaFormatLayer = CParaFormatLayer::NewL();CCharFormatLayer *iCharFormatLayer = CCharFormatLayer::NewL();// Set up to-do item dataiTodoItem = CAgnTodo::NewL(iParaFormatLayer, iCharFormatLayer);iTodoItem = (CAgnTodo *)(aEntry->CastToTodo());priority = iTodoItem->Priority();duedate = iTodoItem->DueDate();// Start the protocoliAppUi->SetProgress(_L("Starting the protocol"));buffer.Copy(KReady);Send(buffer);iSendingState = ESendingState1;}The SendItem() function receives a to-do list entry (the parameterfrom the CAgnEntry class), prepares it for sending, then calls a Send()function to send the object through the serial port.The Send() function is defined as follows:void TodoXferSerialAO::Send(const TDes8& aText){TInt len;TBuf8<100> buffer;len = aText.Length();// Send the lengthbuffer.SetLength(0);buffer.Append((TChar)(48+len));buffer.Append(aText);commPort.Write(status, buffer, len+1);SetActive();}There are some interesting parts of this implementation.
First, note thestructure of the code: it sets up some parameters for serial communication86PROCESSES AND THREADSand then calls Write(). This is an asynchronous call that returnsimmediately, beginning the communication process in parallel. Secondly,we use a variable – status – to remember the state we are in. Finally,notice the use of SetActive() at the end of the code. When this systemcall is performed, the active object’s execution is terminated and thethread is placed on a waiting queue.Once we have started an active object and turned over control tothe scheduler, we need a way to continue its execution wheneverI/O operations complete.
This is found in the implementation of theRunL() function. The most common pattern embraced by this functionis essentially to use one big switch statement, based on the value of thestate variable. Each case in the switch statement looks something likethis:case ESEr1:if (status == KErrNone){if (buffer.equals(KOk)){iSendingState = ESError; // indicate an error}else{iAppUi->SetProgress(_L("Sending the priority"));buffer.Format(KPriorityFormat, priority);Send(buffer);iSendingState = EStateXfer1;}}else{iSendingState = ESError; // indicate an erroriAppUi->SetProgress(KRcvErrMessage);}break;At the beginning of each case, we can assume that the previous I/Ooperation has completed with a value stored in a status variable.
We checkthe status variable to determine if the operation completed successfully.If it was successful, we process the results, engage another I/O operation,and change the state variable for the next invocation of RunL(). If ithas not completed successfully, we must deal with it somehow – perhapsaborting the active object or resetting the communication stream. At theend of the case, if we want to continue, we must call SetActive()again.EXERCISES874.3 SummaryThis chapter discussed the concepts of working with processes andthreads in an operating system.
We began the chapter by examining theprocess concept and how much of a process’s conceptual and actualimplementations are derived from the process control block. We definedhow the operating system handles processes and how that handling hassome difficulties in implementation.
We then defined threads and showedhow threads relate to and improve upon processes. User-level threadshave implications about kernel threads and we defined how these relateto each other. We also discussed the Symbian OS concept of activeobjects as special versions of threads.We discussed concepts of implementation and programming of processes, threads and active objects.
Processes use concepts of forking andjoining and we discussed how to program this type of activity in Linux.We also showed how threads can be programmed. We concluded thechapter by discussing some programming issues with active objects inSymbian OS.We have left the topic of how processes and threads are scheduled toChapter 5.Exercises1.Give examples of multithreading from the applications that you useevery day. Describe how you think each example would work if asingle thread of control were to be used.2.Consider situations where multithreaded applications would not bemore useful than singlethreaded applications.