Search code examples
c++tbb

How to get tasks working with TBB


The code below compiles but appears to get stuck somewhere in the tasks I make with Intel TBB. It simply runs and displays nothing and I have to kill the program to end it. Basically, I modelled this after an example in a book and I probably did it incorrectly. What am I doing incorrectly with these tasks? I am using g++ 4.8.4 and think I am using TBB 3.9.

/*
    g++ test0.cpp -o test0.out -std=c++11 -ltbb
*/

#include <iostream>
#include "tbb/task_scheduler_init.h"
#include "tbb/task.h"

using namespace tbb;

long serial_fibo(long n) {
    if(n < 2) {
        return n;
    } else {
        return serial_fibo(n - 1) + serial_fibo(n - 2);
    }
}

class Fibo_Task: public task {
public:
    const long n;
    long* const sum;

    Fibo_Task(long _n_, long* _sum_) :
        n(_n_), sum(_sum_) {}

    // override virtual function task::execute
    task *execute() {
        if(n < 4) {
            *sum = serial_fibo(n);
        } else {
            long x = 0, y = 0;

            // references x
            Fibo_Task& a =
                *new(task::allocate_root())
                    Fibo_Task(n - 1, &x);

            // references y
            Fibo_Task& b =
                *new(task::allocate_root())
                    Fibo_Task(n - 2, &y);

            // two children and another to wait
            set_ref_count(3);
            spawn(a);
            spawn_and_wait_for_all(b);
            *sum = x + y;
        }
        return NULL;
    }
};

long parallel_fibo(long n) {
    long sum;
    Fibo_Task& a =
        *new(task::allocate_root())
            Fibo_Task(n, &sum);

    task::spawn_root_and_wait(a);
    return sum;
}

int main() {
    task_scheduler_init init;

    long number = 8;
    long first = serial_fibo(number);
    long second = parallel_fibo(number);

    std::cout << "first: " << first << "\n";
    std::cout << "second: " << second << "\n";

    return 0;
}

Solution

  • You allocated 'root' tasks instead of 'child' tasks. The difference is that allocate_root() creates independent task which does not point to anything as its successor. And thus the wait_for_all() does not receive corresponding signals that the tasks are completed and thus hangs.

    You can find the correct original example in the TBB documentation here.

    Or you can fix yours by adding a... and b.set_parent(this) which effectively fixes the difference between allocate_root() and allocate_child() as I implemented here.