When all the work is done, the work pool returns a null, and the work manager reacts by doing a callback to its parent problem's signalDone() method. In the signalDone() method, the parent problem sets up the next stage of the computation by creating new work (or new managers as need be). Thus, when the signalDone() method returns to the manager which called it, the manager can proceed to give out the new work.
The signalDone() method provides a simple mechanism for implementing barrier synchronization. That is, it allows programmers to separate blocks of parallel computation where one block must be computed completely first before the other. For example, in the factoring application described below, the parent problem has a list of target numbers to be factored, and its signalDone() method is used to move from one target to the next, while making sure that all the results from the previous one have been solved before moving on.
Note that the parent problem in this case serves the role of the program object described in Sect.3. In this case, the program object is passive. Although not yet implemented, an active program object with its own thread managing several sets of managers, is also possible, and can provide an easier and more flexible way to write complex applications.