In the previous chapter, the model was described as having two main foundations, planning and execution. These two elements persist in the model to be presented. However, one of these, execution, will be based on an analogy drawn from a
different system, since the one described previously has been shown to be inadequate for the purposes. The other element, planning, stays essentially the same.
6 . 1 . 1 . Execution
In the section covering Vertical-Debugging above (4.2.), the problem of the level of description supported by the data with respect to non-preemption was discussed. The problem is that the data will not provide for messages to be specified at the low level demanded by the observed changes of task. It would be possible to persevere with the current analogy, but the model would become inelegant, and inelegance can mean unnecessary assumptions and side-effects. Consequently, it is necessary to identify a new mechanism upon which to base this part of the model.
A major new operating system was announced by Microsoft (the same company responsible for Windows), at about this stage in the development of the model. This system, known as OS/2, provides a graphical, WIMP, interface on similar
technology, with a similar object metaphor for the programmer. The crucial difference is the mechanism by which is shares the unitary processor amongst competing tasks. The published account of OS/2 (Letwin, 1988) describes a preemptive multitasking mechanism built around threads of differing priorities. As much of this as is relevant is described shortly. It is conceivable that OS/2 might have been recruited at an earlier stage had it been available.
A multitasking mechanism based on preemption is one in which the shared processor can be snatched away from a task and given to another without regard to the ongoing task. Simple time-slicing would be one example of a preemptive mechanism.
However, the particular preemptive scheme used in OS/2 is more sophisticated, and geared towards ensuring that the processor spends most of its time where it is actually needed (something which is not true in the case of time-slicing).
To achieve this, it introduces the concept of threads. Computer programs consist of many sequences of instructions, typically conditionally linked together. A particular path through such a set of sequences at run time is referred to as a thread. Note that it is possible for there to be more than one such thread associated with any program at a time. It is important to remember that the actual sequence of instructions which makes up a thread is likely to be only fully specifiable post hoc (because of the conditional branches).
^ n a p ie r
To the OS/2 system, then, multiple tasks are represented as multiple threads, where each thread must be given the attention of the processor in order for that task to make progress. This sharing is optimised using a system in which there are different categories of thread, together with priorities associated with each one. There are three main categories of threads, with one category being usefully divided into two sub categories.
Being an interactive system, the thread categories are based on the assumption that the threads associated with the programs currently in use by the user, i.e. in the active screen group, are the most important, and therefore should have the highest priority. The first category is the General category, which in turn consists of the two
subcategories a) Foreground and Interactive, and b) Background. The majority of threads fall into one of these two groups. The Foreground category are those threads associated with the currendy active screen group, with the Interactive classification referring to the particular thread which is receiving user input. This thread has a higher priority than the other foreground threads, which in turn have higher priorities than the background threads. The latter are associated with tasks which are not part of the user’s active screen group.
The remaining two classes are more specialised. The Time-Critical category is for threads which must be run at particular intervals, for instance, and the Low Priority category is exactly what it says - a category for the threads of the lowest importance. The allocation (and preemption) of the processor is the responsibility of a scheduler. The scheduler is able to modify the priorities of threads in the general category as necessary (see below), and is responsible for preempting the processor from a thread to ensure that the highest possible priority thread is always running.
In general, the interactive thread will have the highest priority and thus the processor whenever it needs it. After that, other foreground threads will be allocated the processor, accordingly, followed by any background threads. Any low-priority threads will mop-up any leftover processor time if there are no other categories of higher importance.
Time-critical threads periodically raise their priority high enough to preempt the processor, but with the caveat that they must not hold on to it for very long, otherwise the interactive thread will appear disrupted to the user.
Simple priority allocation in this way is not sufficient. Without any extension, the above scheme would mean that once the high priority interactive category thread gained the processor, it would only lose it to a time-critical thread. To overcome this, OS/2 introduces the concept of blocking. A thread blocks when it must wait for,
v^napier h
e.g., a device operation (reading from disk, user input, etc). A blocked thread surrenders the processor, which thus passes to the next unblocked thread with the highest priority. In this respect it is similar to a non-preemptive scheme. As soon as the blocked thread becomes unblocked again, however, the processor is snatched back by the higher priority thread.
While the above is only a limited account of the relevant parts of OS/2, leaving out many details which are not thought to be pertinent, it necessarily covers more than will be recruited to the model for reasons of providing a consistent account. The intention is to use the concept of threads and blocking, with differing priorities, and also to an extent, different categories of threads (in particular the special classes, such as time critical threads).