Concepts with Symbian OS (779878), страница 18
Текст из файла (страница 18)
Symbian OS threads can78PROCESSES AND THREADSoperate in kernel mode via system calls. Symbian OS also adds exception handling and exit signaling to the implementation of Symbian OSthreads.Symbian OS threads implement their own set of states on top of thenanothread implementation to reflect the new ideas built into SymbianOS threads. Symbian OS adds seven new states for threads, focused onspecial blocking conditions that can happen to a Symbian OS thread.These special states include waiting and suspending on semaphores,mutex variables and condition variables (see Chapter 6).
Rememberthat, because of the implementation of Symbian OS threads on top ofnanothreads, these states are implemented in terms of nanothread states,mostly by using the suspended state in various ways.Processes, then, are Symbian OS threads grouped together under asingle PCB structure with a single memory space. There may be onlya single thread of execution or there may be many threads under onePCB. Concepts of process state and process scheduling have already beendefined by Symbian OS threads and nanothreads.
Scheduling a process,then, is really implemented by scheduling a thread and choosing the rightPCB to use for its data needs.Symbian OS threads organized under a single process are connectedin several ways:• a main thread is marked as the starting point for the process• threads share scheduling parameters; changing parameters for theprocess changes the parameters for all threads• threads share memory-space objects, including device and otherobject descriptors• when a process is terminated, the kernel terminates all threads in theprocess.Active objects are specialized forms of threads and are implementedin a special way to lighten their burden on the operating environment.Remember that active objects are organized so that when they arebrought back from a blocked state, they have a specific entry point intotheir code that is called.
Since they run in user space, active objects areSymbian OS threads. As Symbian OS threads, active objects have theirown nanothreads and can join with other Symbian OS threads to form aprocess to the operating system.PROGRAMMING WITH PROCESSES79As active objects are Symbian OS threads, one can ask what theadvantage is of using them.
The key to active objects is in scheduling,which we cover in Chapter 5. It is important to realize, however, whereactive objects fit into the Symbian OS process structure. When a threadmakes a system call that blocks its execution while in the waiting state,the operating system still needs to check the thread. The operating systemspends time between context switches checking waiting processes todetermine if they need to move to the ready state. Active objects wait fora specific event. The operating system does not need to check them butmoves them when their specific event occurs. The result is less threadchecking and faster performance.4.2 Programming with ProcessesHow we think about processes affects how we program those processes. Akey element, then, to understanding how processes work is to understandhow they are programmed.
This means studying the system calls andthe programming patterns that are used when processes and threads aremanipulated.There are several types of programming methods for processes. Anolder, more traditional way focuses on processes. Another method incorporates threads into this conventional programming model. A third wayof programming uses specialized thread objects such as Symbian OSactive objects.
These are all illustrated in this section.The Conventional ModelThe conventional model works at the process level. Processes are createdby an operation called a fork, which creates a new process by buildinga new PCB and placing the new process in the ready queue. The forkoperation is complemented by a ‘join’ or ‘wait’ operation. As shownin Figure 4.6, the fork operation splits the execution of one processinto several and the join operation joins the process executions backinto one. In Figure 4.6, at the dotted line labeled ‘A’, there are fourprocesses executing.
Join operations cause the subprocesses to terminateand combine their executions. By the end of Figure 4.6, there is a singleprocess executing again.In Linux, for example, a process creates a new process by calling thefork() system call. This system call creates a new process by cloningthe current process’s PCB. The result is two processes that look identical;80PROCESSES AND THREADSforkforkforkAAjoinjoinjoinFigure 4.6The interaction between fork and join operationsthe new one is an exact copy of the old one.
Both processes continueexecution at the point of the fork() system call. The child knows it is achild because the fork() call returns a zero; the parent knows it is theparent because the fork() call returns a non-zero result, which is theprocess ID of the child process.As an example, consider the following simple code:#include <stdio.h>void main(){PROGRAMMING WITH PROCESSES81int pid, status;pid = fork();if (pid == 0){printf("This is the child!\n");sleep(60);}else{printf("This is the parent! Child’s PID = %d\n", pid);wait(&status);printf("Child terminated...status = %d\n", status);}}The first executable code line is:pid = fork();Before this line, there is a single process. After this line executes, thereare two processes. For one process, the child, pid has the value 0.
Forthe other process, the parent, pid has a non-zero value that is the processID of its child. In the example, the child simply prints a message, sleepsfor 60 seconds, and terminates. The parent executes the line:wait(&status);which implements a join operation in Linux. A wait() call moves thecaller process to the ready queue until the process for which it is waitingterminates. In this case, the call is waiting for the termination of anyprocess the parent created.Processes terminate in many ways. The normal way for a program toend is to simply run out of code. Most programming languages providefor some kind of call to exit().
In addition to allowing programs andprocesses to use the exit() system call, processes can also terminatetheir children. Signals that tell a process to terminate can be sent arbitrarilybetween processes, but ones sent from a parent to a child process areespecially hard to ignore.In this conventional process model, processes share very few resources.Each newly created process works in its own environment with its ownPCB. This means each process has its own variables, its own access to82PROCESSES AND THREADSresources and its own access to the kernel. What is shared are systemresources such as input/output devices and memory. As we have discussedbefore, operating systems are designed to protect resource access and toshare system resources in a very orchestrated manner, so that multipleaccesses do not corrupt resources. This means that even though a child iscreated by a parent, they are peers from the point of view of the resource.This conventional approach to multiprogramming is very resourceintensive.
The operating system must keep track of each process byrecording and manipulating its PCB. Switching context between processesis expensive, because PCB data must be recorded and moved into and outof memory. Creating processes is also expensive because of PCB creationand the cloning of the parent context.Sharing data between processes is quite difficult. The operating systemputs up a barrier between processes and protects each process fromothers.
Data can be shared in Linux by creating global, shared memorythrough system calls or by creating data channels called pipes that aprocess can share with children that it creates. However, these methodsare special cases and are themselves expensive to the operating system.Consider a sorting algorithm. In a quicksort implementation, an arrayof data elements is split up into pieces and a recursive call is made tothe quicksort algorithm to work on each piece. The quicksort algorithmcan be implemented in a parallel manner, where each recursive call isreplaced by a new process. If we use the conventional model, we can getmany processes involved.
These processes can easily get started on thesorting process, because each has a copy of the data array (as the PCBis cloned). However, when it comes time to put the sorted pieces backtogether, the conventional model makes implementation very difficult.Somehow, only pieces of the data array must be communicated to a singleprocess, which must put everything back together. Parallel versions ofquicksort are rarely implemented with processes.Programming with ThreadsThreads solve many of the difficulties with processes. Threads are easilycreated: the creation process is lightweight because it is not resourceintensive, no PCBs are cloned.