Hardware Reference
In-Depth Information
This solution uses Java threads to simulate parallel processes. With this solu-
tion we have a class producer and a class consumer , which are instantiated in the
variables p and c , respectively. Each of these classes is derived from a base class
Thread , which has a method run . The run method contains the code for the thread.
When the start method of an object derived from Thread is invoked, a new thread
is started.
Each thread is like a process, except that all threads within a single Java pro-
gram run in the same address space. This feature is convenient for having them
share a common buffer. If the computer has two or more CPUs, each thread can be
scheduled on a different CPU, allowing parallelism. If there is only one CPU, the
threads are timeshared on the same CPU. We will continue to refer to the producer
and consumer as processes (since we are really interested in parallel processes),
even though Java supports only parallel threads and not true parallel processes.
The utility function next allows in and out to be incremented easily, without
having to write code to check for the wraparound condition every time. If the pa-
rameter to next is 98 or lower, the next-higher integer is returned. If, however, the
parameter is 99, we have hit the end of the buffer, so 0 is returned.
We need a way for either process to put itself to sleep when it cannot continue.
The Java designers understood the need for this ability and included the methods
suspend (sleep) and resume (wakeup) in the Thread class right from the first ver-
sion of Java. They are used in Fig. 6-26.
Now we come to the actual code for the producer and consumer. First, the pro-
ducer generates a new prime in P1. Notice the use of m.MAX PRIME here. The
prefix m. is needed to indicate that we mean the MAX PRIME defined in class m .
For the same reason, this prefix is needed for in , out , buffer , and next , as well.
Then the producer checks (in P2) to see if in is one behind out . If it is (e.g.,
in
63), the buffer is full and the producer goes to sleep by calling
suspend in P2. If the buffer is not full, the new prime is inserted into the buffer
(P3) and in is incremented (P4). If the new value of in is 1 ahead of out (P5) (e.g.,
in
=
62 and out
=
16), in and out must have been equal before in was incremented.
The producer concludes that the buffer was empty and that the consumer was, and
still is, sleeping. Therefore, the producer calls resume to wake the consumer up
(P5). Finally, the producer begins looking for the next prime.
The consumer's program is structurally similar. First, a test is made (C1) to
see if the buffer is empty. If it is, there is no work for the consumer to do, so it
goes to sleep. If the buffer is not empty, it removes the next number to be printed
(C2) and increments out ( C 3). If out is two positions ahead of in at this point (C4),
it must have been one position ahead of in before it was just incremented. Because
in
=
17 and out
=
1 is the ''buffer full'' condition, the producer must have been sleeping,
and thus the consumer wakes it up with resume . Finally, the number is printed
(C5) and the cycle repeats.
Unfortunately, this design contains a fatal flaw, as illustrated in Fig. 6-27.
Remember that the two processes run asynchronously and at different, possibly
=
out
 
Search WWH ::




Custom Search