The shared buffer is implemented as a circular array with two logical pointers:
in and out. The variable in points to the next free position in the buffer; out
points to the first full position in the buffer. The buffer is empty when in ==
out; the buffer is full when ((in + 1) % BUFFER SIZE) == out.
The code for the producer process is shown in Figure 3.13, and the code
for the consumer process is shown in Figure 3.14. The producer process has a