Search code examples
multithreadingtbbtbb-flow-graph

Can master thread later join the TBB arena group?


Say, there is a master thread that deploys TBB to spawn additional worker threads, as shown in the code snippet below.

The master thread continues with its business, without waiting for arena group to finish. However, the master thread may happen to finish well before the worker threads.

So the logical question is: would it be possible to implement late-join of master thread to the arena group and use its clocks to help out with the remaining work? Any equivalent TBB-based solution to achieve this scenario?

tbb::task_group group;
tbb::task_arena arena(nthreads, 1);

tbb::task_scheduler_init init(nthreads);

arena.enqueue( [&]
{
    group.run( [&]
    {
        ...
    });
});

// Work done on master thread here

// Master thread has finished: can it now join the arena group
// and help with the remaining work?

group.wait();

Solution

  • You cannot do that with task_arena alone, but the combination of task_arena and task_group will work. And your code is almost right, except that you need to

    • call group.wait() within the arena;
    • use arena.execute() instead of enqueue() so that group.run() is surely called before group.wait().

    Here is the fixed sample (and the TBB documentation for task_arena has a similar one):

    tbb::task_group group;
    tbb::task_arena arena(nthreads, 1);
    
    tbb::task_scheduler_init init(nthreads);
    
    arena.execute( [&]
    {
        group.run( [&]
        {
            ...
        });
    });
    
    // Work done on master thread here
    
    // Master thread has finished; now it joins the arena group
    // and helps with the remaining work
    arena.execute( [&]
    {
        group.wait();
    });
    

    It might look somewhat over-complicated, but starts making sense if you consider task_arena an abstraction of workers, not of work. We wanted to add a task_arena::wait() method, but found out that it would be semantically ambiguous ("no free tasks left" does not mean "work is done") and might deadlock if accidentally called by a thread already in that arena. The combination with task_group is free of both these shortcomings due to waiting for a specific group of tasks, not for "all submitted work".