task_arena Class

Summary

Explicit, user-managed task scheduler arena representation.

Syntax

class task_arena;

Header

#define TBB_PREVIEW_TASK_ARENA 1
#include “tbb/task_arena.h”

Description

A task_arena class represents an internal task scheduler object where a number of threads, limited by a maximal concurrency level, share and execute tasks.

The concurrency level of a task_arena is isolated and not affected by previous task_scheduler_init specifications.

Note

The total number of threads created for a process is limited by whichever is largest: the default number of threads for the machine or the value specified by the first task_scheduler_init object. Therefore the number of threads assigned to a task_arena will never exceed that maximum value, regardless of the concurrency level.

Note

A task_arena may get fewer workers and never get the specified number of threads, even if the specified concurrency level is lower than the allowed maximum.

A task_arena object keeps a reference to its internal representation, but does not fully control its lifetime. It cannot be destroyed until it contains tasks and/or other worker threads reference it.

Note

The task_arena constructors do not create the internal arena objects. They are created lazily on first use.

Each user thread that explicitly or implicitly creates a task_scheduler_init object contains an implicit internal task arena object. The tasks spawned or enqueued in an arena cannot be executed in a different arena.

This preview feature requires linkage with the Community Preview library.

Caution

If linking with Community Preview library, always define TBB_PREVIEW_TASK_ARENA. Some other features like task_scheduler_observer can depend on this definition.

Members

namespace tbb {
class task_arena {
public:
    static const int automatic = implementation-defined;
    static int current_slot();
    task_arena(int max_concurrency = automatic);
    task_arena(const task_arena &s);
    ~task_arena();
    void initialize(int max_concurrency);
    template<typename F> void enqueue( const F& f );
#if __TBB_TASK_PRIORITY // TODO: remove???
    template<typename F> void enqueue( const F& f, priority_t p );
#endif
    template<typename F> void execute(F& f);
    template<typename F> void execute(const F& f); // TODO:remove?
    void wait_until_empty();
};
}

Examples

The following example runs two paralel_for loops concurrently; one that is scalable and one that is not. The non-scalable loop is limited to at most 2 threads so that the majority of the threads can be saved for the more scalable loop.

tbb::task_scheduler_init def_init; // Use the default number of threads
tbb::task_arena limited(2);// no more than 2 threads in this arena

limited.enqueue([]{ // use at most 2 threads
    tbb::parallel_for(1, N, unscalable_work());
}); 

// Run another job concurrently with the loop above
// It can use the default number of threads:
tbb::parallel_for(1, M, scalable_work());

limited.wait_until_empty(); // ensure async work is finished

The last line of the above example calls wait_until_empty() to wait for all work in the arena to be completed. If you need to wait for a specific subset of tasks to complete, a task_group can be used as shown below:

tbb::task_arena arena;
tbb::task_group tg;

// Enqueue some job(s) in a task group 
for( int i=0; i<N; ++i)
    arena.enqueue([&,=i] { tg.run( F(i) ) });

// Do some other work ...

// Put the wait for the task group inside execute()
// This will wait only for the tasks that are in
// this arena.
arena.execute([&]{ tg.wait(); }); 

The following table provides additional information on the members of this template class.

Member Description
task_arena(int max_concurrency = automatic)

Creates a task_arena with a specific maximum concurrency limit, if specified.

static const int automatic

When passed to the above constructor, max_concurrency will be automatically set based on the hardware configuration.

task_arena(const task_arena&)

Copies settings from another task_arena instance.

~task_arena()

Removes the reference to the internal arena representation, and destroys the external object. Not thread safe w.r.t. concurrent invocations of other methods.

void initialize(int max_concurrency); Performs actual initialization of internal arena representation overriding concurrency settings. If called on already initialized arena, it has no effect.

Note

The maxmimum concurrency limit is fixed at initialization time and cannot be changed.
template<F> void enqueue(const F&)

Enqueues a task into the arena to process specified functor and immediately returns.

Note

Does not require the calling thread to join the arena; i.e. any number of threads outside of the arena can submit work to the arena without blocking.

Caution

There is no guarantee that tasks enqueued in an arena execute concurrently with respect to any other arena’s tasks.
template<F> void enqueue(const F&, priority_t)

Enqueues a task with specified task priority. Is similar to enqueue( const F& ) in all other ways.

template<F> void execute(F&)

template<F> void execute(const F&)

If possible, the calling thread joins the arena and executes the specified functor, then leaves the arena and returns to previous task scheduler state.

If not possible to join, the call wraps the functor into a task, enqueues it in the arena and waits on an OS kernel synchronization object for task completion.

Note

Any number of threads outside of the arena can submit work to the arena and be blocked. However, only the maximal number of threads specified for the arena can participate in executing tasks.

Note

May decrement the arena's demand for worker threads, causing a worker to leave, and thereby freeing a slot for the calling thread.
void wait_until_empty()

Wait for all work in the arena to be completed. The calling thread joins the arena if possible, in the same way as execute().

Caution

This method waits for all work, even work submitted by other application threads.
static int current_slot()

Returns: The index of the slot that the calling thread is assigned to in its current arena. This can be used, for example, by a task_scheduler_observer to pin threads entering an arena to specific hardware.

See Also