Explicit, user-managed task scheduler arena representation.
class task_arena;
#define TBB_PREVIEW_TASK_ARENA 1 #include “tbb/task_arena.h”
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.
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.
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.
namespace tbb { class task_arena { public: static const int automatic = implementation-defined; static int current_slot(); task_arena(int max_concurrency = automatic, unsigned reserved_for_masters = 1); task_arena(const task_arena &s); ~task_arena(); void initialize(); void initialize(int max_concurrency, unsigned reserved_for_masters = 1); void terminate(); bool is_active(); template<typename F> void enqueue( const F& f ); template<typename F> void enqueue( const F& f, priority_t p ); template<typename F> void execute(F& f); template<typename F> void execute(const F& f); void wait_until_empty(); }; }
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(); });
Member | Description |
---|---|
task_arena(int max_concurrency = automatic, unsigned reserved_for_masters = 1) |
Creates a task_arena with certain concurrency limit and some portion of it reserved for application threads. NoteFor the community preview implementation of task_arena, the only valid values for reserved_for_masters are 0 and 1. |
static const int automatic |
When passed as max_concurrency to the above constructor, arena 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 task_arena() instance. Not thread safe w.r.t. concurrent invocations of other methods. |
void initialize();
void initialize(int max_concurrency, unsigned reserved_for_masters = 1); |
Performs actual initialization of internal
arena representation. If arguments are specified, overrides previous concurrency settings.
Has no effect when called on already initialized arena.
NoteAfter the call to initialize, the arena concurrency is fixed and cannot be changed. |
void terminate() | Removes the reference to the internal arena representation without destroying the task_arena object, which can then be re-used. Not thread safe w.r.t. concurrent invocations of other methods. |
bool is_active() | Returns true if the arena has been initialized, false otherwise. |
template<F> void enqueue(const F&) |
Enqueues a task into the arena to process specified functor and immediately returns. NoteDoes 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.CautionThere 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. NoteAny 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.NoteMay 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(). CautionThis method waits for all work in the arena, 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. |