Job level parallelism is also exploited within a single computer by treating a job or several jobs as a collection of independent tasks. For example, several jobs may reside in memory at the same time with only one in execution at any given time. When that job requires some I/O services, such as a read from disc, the operation is initiated, the job requiring the service is suspended, and another job is put into execution state. At some future time, after the I/O operation has completed and the data is available, control will pass back to the original job and execution will continue. In this example, the CPU and the I/O system are functioning in parallel.
Parallelism at the program level is generally manifested in two ways: independent sections of a given program, and individual iterations of a loop where there are no dependencies between iterations. This type of parallelism may be exploited by multiple processors or multiple functional units. For example, the following code segment calls for the calculation of n sums:
DO 10 I=1,N A(I) = B(I) + C (I) 10 CONTINUE
The sums are independent, i.e. the calculation of does not depend on for any j < i. That means they can be done in any order, and in particular a machine with n processors could do them all at the same time.
Obviously, more complex segments may also be treated in parallel depending on the sophistication of the architecture. This is the level of parallelism with which we will primarily be concerned in this book.