Recycling the parent as a child

This style is useful when the child inherits much of its state from a parent and the continuation does not need the parent’s state. The child must have the parent’s type. In Example 9-6, C is the type of the continuation, and it must derive from the class task. If C does nothing but wait for all children to complete, C can be the class empty_task.

Example 9-6. Recycling parent as a child

task* T::execute() {
    if( not recursing any further ) {
        ...
        return NULL;
    } else {
        set_ref_count(k);
        // Construct continuation
        C& c = allocate_continuation();
        // Recycle self as first child
        task& tk = new( c.allocate_child() ) T(…); tk.spawn();
        task& tk-1 = new( c.allocate_child() ) T(…); tk-1.spawn();
        ...
        task& t2 = new( c.allocate_child() ) T(…); t2.spawn();
        // task t1 is our recycled self.
        recycle_as_child_of(c);
        ... update fields of *this to state subproblem to be solved by t1
        return this;
    }
}

Here are the key points of the pattern:

  • The call to set_ref_count uses k as its argument. There is no extra 1, as there is in blocking style.

  • Each child task except for t1 is allocated by c.allocate_child. It is critical to use c.allocate_child and not (*this).allocate_child; otherwise, the task graph will be wrong.

  • Task t1 is recycled from the parent, and hence gets the parent’s state without performing copy operations. Do not forget to update the state to represent a child subproblem; otherwise, infinite recursion will occur.

Get Intel Threading Building Blocks now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.