• Aucun résultat trouvé

Figure 4.33 Implementing the Runnable interface

Dans le document [ Team LiB ] (Page 189-199)

}

Figure 4.33 Implementing the

Runnable

interface.

public class PrintThread2 implements Runnable {

public static void main (String args[ ]) throws InterruptedException { Thread a = new Thread (new PrintThread2("a"));

The behaviour of Java threads varies according to the operating system of the host platform. In particular, on some systems Java threads are scheduled preemptively and on other systems they are non-preemptive.

It is often useful to be able to make a thread delay execution for a period of time. This might be useful for example where a thread controls some animation in order to ensure that the relevant movements don't happen too quickly. The Java thread class has two sleep methods which allow for a delay, the sleep period can be specified in milliseconds or in milliseconds and nanoseconds. Examples of the sleep method are illustrated in Figures 4.32 and 4.33. Whilst in Figure 4.33 our PrintThread2 class does not inherit the method sleep from Thread, we are still able to make use of the sleep method by invoking it as Thread.sleep ().

The sleep method invocations in Figures 4.32 and 4.33 also illustrate Java's exception-handling mechanism. In Java there are classes to represent exceptions. Exceptions can be dealt with as in Figure 4.32 by using the try{...} catch () {...} construct that Java provides. In Figure 4.32, if an exception belonging to class InterruptedException occurs whilst the thread is sleeping, the catch clause will be executed. Alternatively we can specify that a method should terminate when particular exceptions occur, deferring responsibility to the invoking method. The syntax for this is illustrated in Figure 4.33, where the method main is declared as throwing an InterruptedException.

Java provides classes defining a range of exceptions, and programmers are free to extend the existing hierarchy of these.

A thread can wait for the completion of some thread t by applying the join method to t, i.e. t.join(). The example uses the join method to make the main thread delay its execution until firstly thread a terminates and then thread b terminates. The join method invocation once again illustrates Java's exception-handling mechanism, the details being similar to those described above.

Java threads have priorities associated with them. Threads of higher priority are given preferential treatment over threads of lower priority. A thread's priority can be set using the thread method setPriority and determined by using the thread method getPriority. The Java threads class provides a number of other methods, some of which we will encounter in later chapters.

[ Team LiB ]

[ Team LiB ]

4.19 Summary

In Chapter 1 we established the requirements for implementing system software:

Support for separate activities.

how the process abstraction is supported by language runtime systems and operating systems;

the relationship between these process implementations and the implications of this relationship.

The requirement to support separate activities (1) has therefore been explored in detail. The reader should now be able to think of a software system in terms of a set of concurrent processes.

The requirement for the management of separate activities (2) has been discussed. We have seen how a process activation may be created from a process specification. We have discussed the need for process termination.

The support for the related activities to work together in a system (3) has been motivated, but has yet to be addressed systematically.

We have seen that a coroutine or process scheme where only user threads are implemented may allow simplifying assumptions to be made about the consistency of shared data structures on a coroutine or process switch. This also holds for kernel threads when they are scheduled non-preemptively, but only if the system runs on a uniprocessor. We discuss the problem in general in Part II.

The ability of a system to meet timing requirements (4) must obviously depend on hardware characteristics. It has been shown that this ability also depends on the support for concurrency provided by the operating system. If this basic level of support is not given, a real-time system cannot be programmed. It is therefore necessary to know whether the operating system schedules its processes preemptively. If not, critical timing requirements cannot be guaranteed to be met. Preemptive scheduling is a necessary condition for timing guarantees to be met, but is by no means sufficient. It is also necessary to know a bound on the time that can be spent executing the operating system. Scheduling algorithms were discussed, both for general-purpose and for real-time systems.

We have explored the options for implementing systems. Either components are written in sequential programming languages and system calls are provided to support their interaction or a concurrent programming language is used.

In the former case there is a potential portability problem. Systems developed in this way can only run on operating systems which have compatible system calls for this purpose. Standard library packages have been developed to provide a convenient interface for some programming languages on some operating systems.

In the latter case we have examined the possible relationship between the processes (or coroutines) specified in a concurrent programming language and the processes supported by the operating system. This was shown to be operating system dependent.

The overhead involved in switching between the separate activities of a concurrent system should be taken into account. This is lowest for coroutines and language-only processes, highest for operating system (heavyweight) processes (when each has a separate address space), and intermediate for switching between kernel threads of the same process.

An important issue emerges from the discussion in this chapter. Even if a system is to be written in a high-level language it is necessary to have knowledge of:

the relationship between the language runtime system and the operating system;

details of the operating system support for processes;

some aspects of the hardware on which the system will run; for example, is it a uniprocessor or a multiprocessor?

Study questions

S4.1

Give two methods of allocating processes.

a.

What is the purpose of a process management module?

b.

S4.2

What is a virtual processor?

a.

Why must a process be able to execute a WAIT (anEvent) operation?

b.

Distinguish between the process states called blocked, runnable and running.

c.

What is meant by non-preemptive scheduling? Under what circumstances is it useless?

d.

S4.3

Under what circumstances will a process relinquish a processor?

a.

What is a process descriptor and why is it needed?

b.

What is a context switch?

c.

S4.4

What actions are taken by the method that implements the WAIT (anEvent) operation on process descriptors?

a.

What causes the SIGNAL () operation to be invoked?

b.

What actions are taken by the routine that implements the SIGNAL () operation on events?

c.

Why is a record of events kept in a process's descriptor?

d.

Under what conditions does a race condition occur?

e.

What is an atomic operation? Why must WAIT () and SIGNAL () on events be implemented as atomic operations?

f.

S4.5 Distinguish between the process level and the process implementation level for the support of concurrent processes.

S4.6

Distinguish between a lightweight and a heavyweight process.

a.

What is a multi-threaded operating system?

b.

S4.7

Describe in your own words what is being represented in the three figures shown in Figure 4.17.

a.

Use Figure 4.17 to illustrate what is meant by the statement that processes are the unit of resource allocation.

b.

Why is it necessary to know whether or not language-level processes are known to the operating system?

c.

S4.8

What three segments are usually found in the memory allocated to a process?

a.

Distinguish between an activation record and a stack frame. What is contained in a stack frame? How long does a stack frame last?

b.

S4.9

What is a synchronous system call?

a.

What problem is caused if an operating system provides only synchronous system calls, and runs as a single operating system process?

b.

Why must an operating system that supports interrupts allow the preemption of processes?

c.

What problem arises if a process is forcibly suspended, i.e. not voluntarily?

d.

Exercises

4.1 Discuss how you would wish to allocate processes in the systems that were described in the Introduction, for example:

an industrial process control system

a parallel searching algorithm to run on a shared-memory multiprocessor e.

a multiphase compiler to run on a shared-memory multiprocessor.

f.

4.2 How would you simulate one processor per process in a uniprocessor and a shared-memory multiprocessor?

4.3 List everything that might be considered part of the state of a process. Which of these items must always be in main memory and which could be swapped out to backing store when the process was not running?

4.4

Design a method of implementing synchronization between a peripheral and a single process which is dedicated to managing it.

a.

Design a method of implementing synchronization between a peripheral and a process which is currently waiting for it to deliver data but is not dedicated to this task.

b.

Design a method of implementing synchronization between any hardware device and one or more processes.

c.

4.5 Design a data structure which implements the representation of the processes known to an operating system. You should consider whether your system has a significant number of dedicated system processes and, if so, whether they will be held separately from user processes. What operations would you expect to provide at the interface of a process management module?

4.6

When does a general schedule need to be carried out in a multi-access system?

a.

How can a process in a multi-access system be scheduled differently when it is in a compute-bound phase from when it is doing input or output?

b.

How many processes would you expect to be active in a single-user workstation, a dedicated gateway computer and a dedicated file server?

c.

How would you expect processes to be scheduled in a multimedia workstation (see Section 1.1)?

d.

4.7 How does scheduling for real-time systems differ from scheduling for multi-access systems?

4.8 What approaches can be taken to scheduling for shared-memory multiprocessor systems?

4.9 Recall the layered communications software described in Chapter 3. Consider the situation when several user processes have made requests for network input or output.

How might the layers be executed by processes?

a.

How might synchronization between user-level processes and the arrival or transmission of data at the network be arranged?

b.

Where might network buffers be located with respect to the ISO layers?

c.

Why would it be a bad idea to have a process execute each of the ISO layers?

d.

4.10 For a given modular operating system structure, what is the minimum set of dedicated, resident system processes that can be used? How does the rest of the operating system get executed in this case?

How would you design to maximize the number of dedicated system processes?

For both of the approaches indicated above, discuss where a separate address space could be used for protection purposes. Assume that the system provides a mechanism for a process to make requests of the operating system. We have studied one such mechanism in Section 3.3.2. We shall expand on this in Part II.

4.11 In what circumstances might it be advantageous to use several threads of control within a single process?

4.12 Section 4.9 introduced a process management module and pointed out that, as this module implements the process abstraction, it cannot itself be implemented in terms of processes.

Within an operating system, the interface operations of the process management module may be called as simple procedures. In Section 4.4, for example, we saw the WAIT () operation on events invoking the BLOCK () operation on processes.

In Section 4.10 it was mentioned that an operating system might be executed by a set of system processes taking users' requests or might instead be executed 'in-process'. For both of these models of execution, discuss how the invocation of process management can be incorporated into the model. (The problem to address is, if you are executing the operating system yourself, what happens when you block yourself?)

4.13 What aspects of the state of a process are of concern to an operating system and a language system?

4.14 Discuss how a sequential programming language can be used to implement a concurrent system. What assistance would you expect from a library package and operating system? What are the advantages and disadvantages of using a concurrent programming language?

4.15 What is the essential difference between coroutines and processes? If a concurrent program is to run on a uniprocessor machine, what advantages are there in using a language which supports processes? When might coroutines offer an advantage?

4.16 What are the potential problems of using a language-level 'threads package' when the operating system sees only one process? Why might such a scheme be inappropriate for a shared-memory multiprocessor?

4.17 What are essential requirements for real-time response to be achieved?

4.18

What is meant by a static specification of processes in a programming language?

a.

How would you expect a static approach to be reflected in the syntax of a language?

b.

How can dynamic process creation and deletion be supported in a concurrent programming language?

c.

How might a parent process determine properties of a child process it creates, such as its name or identifier?

d.

How might a parent process be given control over a child process once it has been created?

e.

4.19 You are working in an environment where application developers need to be able to use different scheduling algorithms. Which thread architecture would be most suitable and why?

4.20 Are there any disadvantages arising from using only kernel threads in an application?

4.21 Discuss the pros and cons of multiplexed threads compared with scheduler activations.

4.22 Discuss why soft real-time requirements, such as those that involve dynamically arriving continuous media, might best be met with a combination of user-level and kernel-level threads.

[ Team LiB ]

[ Team LiB ]

Chapter 5. Memory management

5.1 Memory management

5.2 The memory hierarchy

5.3 The address space of a process

5.4 Segmented virtual memory

5.5 Paged virtual memory

5.6 Combining segmentation and paging

5.7 Operating system data structures

5.8 An example of a memory management unit (MMU)

5.9 Memory management in system design

5.10 Summary

One of the main functions of the operating system is to supply the resources that applications need during their execution. In Chapter 4 we saw how this can be done for CPU processing time by using a scheduler to switch between processes, giving each the illusion of continuous execution. In this chapter we consider the other main physical resource associated with process execution: the memory used to hold its code and data.

Typically, processes will be initiated through a graphical interface, or a character-based tool, which receives a command to run a program and causes the operating system to create a new process to execute it. At some stage memory must be allocated to hold the program that is being executed; subsequently more memory might be required beyond this initial allocation for the data structures that the process creates during its execution. The operating system must keep track of free physical memory, recording the allocations it has made to each process and allowing that space to be reclaimed when the process exits. As well as sharing the physical memory between processes, we see how the operating system can give the illusion that there is more memory available than is actually fitted to the computer.

[ Team LiB ]

[ Team LiB ]

5.1 Memory management

We first take an architectural view of main memory in the context of the storage hierarchy of a computer, and then go on to study issues such as protection and sharing which are relevant to concurrent systems design. We are concerned with two distinct kinds of memory management: first of all the logical address space that is available to a particular process and then the physical memory or main memory of the machine on which that process is running.

Instructions must be in main memory in order to be fetched and executed by a processor. Any data operand referenced by an instruction must be in main memory for the instructions to execute successfully. Our expectations of what 'a reasonable amount of main memory' is have changed over the years and will continue to do so, roughly: 1970, 64 kbytes; 1980, 1 Mbyte; 1990, 16 Mbytes; 2000, 1 Gbyte; 2010,

… ? There are already 4-gigabit main memory DRAM devices available and many different options for high capacity disk storage.

Incidentally, although the size of memory expected in a desktop computer has risen dramatically, the cost of the usual amount to fit at any one time has remained broadly constant.

From a system designer's point of view an important property of main memory is that it is in general volatile; that is, if there is a power failure the information stored there is lost. This is a daunting prospect if one has 512 Mbytes of it! Disk storage, on the other hand, is non-volatile and much system design effort is concerned with writing sufficient information safely out to disk to guard against loss of main memory on a crash. We return to this topic in Chapter 15, and throughout Part III. Although specialized non-volatile memory units are available, they are much more expensive than conventional memory and are not usually part of commodity systems.

The appendix gives some examples of early operating systems' use of memory management and the system case studies will show the approach taken in current systems.

[ Team LiB ]

[ Team LiB ]

5.2 The memory hierarchy

Figure 5.1 shows a typical computer system's memory hierarchy. There is a trade-off involved in using storage devices which involves size, speed and cost. The CPU registers are the fastest but smallest store. A large proportion of the machine's instructions will access data from CPU registers and compiler writers must organize their use to optimize program execution time. The detailed design of the processor and the hardware-controlled cache are not our concern here but as system designers we need a broad view of current and projected sizes and speeds. An excellent summary is given in Hennessy and Patterson (2003).

Dans le document [ Team LiB ] (Page 189-199)