Parallel Programming Guide for HP-UX Systems

Parallel synchronization
Synchronizing code
Chapter 8 161
The section of code where the input buffer is copied into the input
queue, however, must be protected by gates to prevent any threads
from trying to read the input queue while it is being filled.
The other seven tasks perform computational work, receiving their input
from and sending their output to task 1’s queues. If a task acquires a lock
on the input queue, task 1 cannot fill it until the task is done reading
from it.
When task 1 cannot get a lock to access the input queue code, it tries
to lock the output queue code.
If it gets a lock here, it can copy the output queue into the output
buffer array and relinquish the lock. It can then proceed to empty the
output buffer.
If another task is writing to the output queue, task 1 loops back and
begins the entire process over again.
When the end of the input file is reached, all computation is
complete, and the output queue is empty: task 1 is finished.
NOTE The task loops on DONEIN (using INDONE()), which is
initially false. When input is exhausted, DONEIN is set to
true, signalling all tasks that there is no more input.
The INDONE() function references DONEIN, forcing a memory reference. If
DONEIN were referenced directly, the compiler might optimize it into a
register and consequently not detect a change in its value.
This means that task 1 has four main jobs to do:
1. Read input into input buffer—no other tasks access the input buffer.
This is done in parallel regardless of what other tasks are doing, as
long as the buffer needs filling.
2. Copy input buffer into input queue—the other tasks read their input
from the input queue, therefore it can only be filled when no
computational task is reading it. This section of code is protected by
the INGATE gate. It can run in parallel with the computational
portions of other tasks, but only one task can access the input queue
at a time.