Wiley.Developing.Software.for.Symbian.OS.2nd.Edition.Dec.2007 (779887), страница 56
Текст из файла (страница 56)
In fact, multipleprograms can have process handles open to the same process, and allthese programs could use Logon() – and so be notified when that singleprocess ends.9.1.11 Other Symbian OS Process FactsThe following are other facts concerning processes:•As described in Chapter 3, switching between threads in differentprocesses (and thus requiring a process switch) is expensive comparedwith switching between threads within the same process. The reasonis that a process switch requires that the data areas of the twoprocesses be remapped by the Memory Management Unit (MMU).Switching between threads in the same process involves no suchmemory mapping changes.•GUI applications are processes.•The emulator does not actually run multiple Windows processes sinceit executes completely as a single process.
However, the emulator willsimulate processes using Windows threads (Symbian OS v9 does thistransparently when you use the RProcess API).9.2 Using Threads on Symbian OSThreads form the basis for multitasking and allow for multiple sequencesof code to execute at once. You can create multiple threads in yourUSING THREADS ON SYMBIAN OS287program for parallel execution. However, in many cases the better wayto go is to use asynchronous functions and active objects, so consideryour use of threads carefully.While Symbian OS relies on threads to implement its multitaskingcapabilities, you’ll find that using multiple threads in your own programcan sometimes be a problem.
One reason is that some Symbian OSobjects can only be used in the thread in which they are created. Acommon example is that only the main thread in a GUI program candraw to the screen – other threads can require a complex handshakingscheme to coordinate with the main GUI thread for screen updates.So while operating systems such as Linux and Windows rely heavilyon creating separate threads for applications, in Symbian OS it’s best toavoid using real threads and instead use active objects (see Chapter 8).This is because active objects can simulate multithreaded behavior, whileactually running in a single thread – thus avoiding threading problemssuch as the ones I mentioned, and others such as synchronization andre-entrancy.However, you may find that creating your own threads is the bestsolution in some situations.
Having an understanding of the way they workalso helps with understanding Symbian OS and its various frameworksbetter.Symbian OS provides the RThread API class for creating and managing threads. Like RProcess, RThread is a handle class and the actualthread object is owned by the kernel. Like RProcess, RThread is alsoinstantiated directly, and usually on the stack.Below is an example that creates and starts a thread using RThread:TInt ThreadFunc(TAny *){for (TInt i=0;i<10;i++){_LIT(KThread, "Thread");User::InfoPrint(KThread);User::After(4000000);}return(0);}void StartThreadL(){RThread thd;_LIT(KMyThread, "MyThread");User::LeaveIfError(thd.Create(KMyThread,ThreadFunc,KDefaultStackSize,NULL,NULL));thd.Resume();}Function StartThreadL() will create a thread at function ThreadFunc().
A thread is created in the suspended state, so, to start thethread, you need to call the Resume() method. Once thd.Resume()288PROCESSES, THREADS, AND SYNCHRONIZATIONis executed, a separate thread starts at ThreadFunc() while the creatingthread continues and returns from StartThreadL().
The created threadwill display an information message to the emulator screen (the messageis seen at the top right-hand corner, and displays for a couple of secondsthen disappears) 10 times, at intervals of four seconds, and the functionwill then exit, thus ending the thread. So after StartThreadL() returns(after the thd.Resume()), you have two threads of execution within theprocess.Note that the thread runs in the same process as StartThreadL(),so it has access to any public variables within the process – but, asmentioned, some Symbian objects created in one thread cannot be usedin another without causing a panic. For example, if you have a simpleconsole application, you cannot pass the CConsoleBase pointer to thesecond thread when you start it, for it to use to write to the screen.
Asalready mentioned, you also cannot draw to the screen from a threadother than the main thread of the GUI application.9.2.1 Creating a ThreadThe RThread::Create() method is used to create a new thread.Threads are not contained in separate executable files as processesare – they execute code in their parent process executable – however,each thread executes as an independent execution stream.
A thread isassociated with a particular function in the process, and that function’sname is specified as an argument to the Create() method. The execution stream starts at that function call and ends when the functionreturns.Let’s look at the RThread::Create() method in more detail. Thereare a few overloads of this function, but they vary by only minordifferences.TInt Create(const TDesC& aName, TThreadFunction aFunction, TIntaStackSize, RHeap* aHeap, TAny* aPtr,TOwnerType aType=EOwnerProcess)•aName defines the name of the thread.
This name can be used whenopening up a handle (via another RThread) to this thread fromanother thread. This name will also appear in the ‘Application Closed’dialogs if a panic occurs within the thread.•aFunction specifies the function where thread execution starts.TThreadFunction is defined as:typedef TInt (*TThreadFunction)(TAny *aPtr);USING THREADS ON SYMBIAN OS289•Upon return from this function, the thread automatically ends.RThread::ExitReason() can then be used to obtain the function’s return value.
Note that the process it was running in willcontinue to execute.•aStackSize defines the size of the stack used by the process inbytes. The constant KDefaultStackSize can be used to indicate adefault stack size.• aHeap passes a heap via an RHeap object pointer. If the value isNULL, the heap of the creating thread is used. Note that there areother versions of Create() that allow a separate heap to be createdautomatically and function arguments are supplied for the minimumand maximum sizes of this heap.• aPtr specifies the argument passed to the thread function defined inaFunction.
NULL can be used if no argument is used.• aType is EOwnerProcess by default. This indicates that thisRThread handle can be used by any thread within the current process. aType can also be set to EOwnerThread to indicate that thisRThread instance can only be used by the thread it was created in.Like RProcess::Create(), RThread::Create() returns KErrNone if successful and a system error code otherwise.9.2.2 Opening an Existing ThreadAs in the case of a process, a handle to an existing thread can be openedby either name or ID using the RThread::Open() method.The following code will open the thread created in the previousexample, and (just to create interest), if it is still running, will suspend it.At this point the thread will be suspended until a Resume() is performed.RThread thd;_LIT(KMyThread, "MyThread");TInt rc=thd.Open(KMyThread);if (rc != KErrNone){/* handle open error */}if (thd.ExitType() == EExitPending)thd.Suspend();...thd.Resume(); // continue thread executionUnlike processes, the system does not append any numbers to theend of thread names so you do not normally need to use the partialname-matching version of the RThread::Open() method.
However,290PROCESSES, THREADS, AND SYNCHRONIZATIONa TFindThread class is supplied that works in the same manner asthe TFindProcess discussed earlier in section 9.1.6, in that it canuse a pattern to match the thread name. A TFindThread object canbe passed to RThread::Open() instead of the thread’s full name, ifdesired.You can also open a thread by passing its integer ID, which is represented by the type-safe class TThreadId. Like RProcess, RThread hasan Id() method that returns the thread’s ID. As in the case of processes,you also need a way of supplying this ID at runtime, to the process andthread that need to open your thread.
This is because thread IDs vary oneach program run, unlike thread names, which are constant.9.2.3 Thread PrioritiesA thread’s priority can be set relative to the priority of its owning processor to an absolute priority, independent of the priority of its owningprocess. Thread priorities are set by the SetPriority() method.Symbian OS defines the following process-relative priorities:• EPriorityNull (-30)• EPriorityMuchLess (-20)• EPriorityLess (-10)• EPriorityNormal (0)• EPriorityMore (+10)• EPriorityMuchMore (+20)• EPriorityRealTime (+30).The default thread priority is EPriorityNormal, which means that thethread’s priority is the same as that of the owning process. The othervalues indicate a thread’s priority in relation to the priority of its owningprocess.