明示的なユーザー管理タスク・スケジューラー領域の表現。
class task_arena;
#define TBB_PREVIEW_TASK_ARENA 1 #include “tbb/task_arena.h”
task_arena クラスは、複数のスレッド (スレッド数は最大並列レベルにより制限される) がタスクを共有し実行する、内部タスク・スケジューラー・オブジェクトを表します。
task_arena の並列レベルは分離されており、以前の task_scheduler_init 仕様の影響を受けません。
task_arena オブジェクトは、内部表現への参照を保持しますが、その生存期間は完全に管理しません。 タスクが含まれるか、ほかのワーカースレッドが参照するまで破棄できません。
task_scheduler_init オブジェクトを明示的または暗黙的に作成する各ユーザースレッドには、暗黙の内部タスク領域オブジェクトが含まれます。 タスク領域にスポーンまたは追加されたタスクは、ほかのタスク領域では実行できません。
このプレビュー機能を使用するには、コミュニティー・プレビュー・ライブラリーとリンクする必要があります。
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();
};
}
次の例は、同時に 2 つの paralel_for ループを実行します。1 つはスケーラブルで、もう 1 つはスケーラブルではありません。 スケーラブルでないループは最大 2 スレッドに制限されるため、ほとんどのスレッドはスケーラブルなループに使用できます。
tbb::task_scheduler_init def_init; // スレッドのデフォルトの番号を使用
tbb::task_arena limited(2);// この領域では最大 2 スレッドのみ
limited.enqueue([]{ // 最大 2 つのスレッドを使用
tbb::parallel_for(1, N, unscalable_work());
});
// 別のジョブを上記のループと並列に実行
// スレッドのデフォルトの番号を使用可能:
tbb::parallel_for(1, M, scalable_work());
limited.wait_until_empty(); // 同期作業が終了することを保証
上記の例は、最後の行で wait_until_empty() を呼び出し、タスク領域のすべての作業が完了するのを待機します。 特定のタスクのサブセットの完了を待機する必要がある場合は、次のように task_group を使用できます。
tbb::task_arena arena;
tbb::task_group tg;
// タスクグループの作業をキューに入れる
for( int i=0; i<N; ++i)
arena.enqueue([&,=i] { tg.run( F(i) ) });
// ほかの作業を行う ...
// execute() の内側でタスクグループを
// 待つようにする
// この arena のタスクのみを待つ
arena.execute([&]{ tg.wait(); });
| メンバー | 説明 |
|---|---|
| task_arena(int max_concurrency = automatic) |
(指定された場合) 指定された最大並列レベルで task_arena を作成します。 |
|
static const int automatic |
上記のコンストラクターに渡されると、ハードウェア構成に基づいて max_concurrency が自動で設定されます。 |
| task_arena(const task_arena&) |
別の task_arena インスタンスから設定をコピーします。 |
| ~task_arena() |
内部タスク領域表現への参照を削除し、外部オブジェクトを破棄します。 ほかのメソッドを同時に呼び出した場合、スレッドセーフではありません。 |
| void initialize(int max_concurrency); | 内部タスク領域表現の初期化を実行し、並列化の設定をオーバーライドします。
すでに初期化されているタスク領域に対して呼び出された場合、効果はありません。
注並列性の最大値と最小値は初期化時に固定され、変更できません。 |
| template<F> void enqueue(const F&) |
指定されたファンクターを処理するため、タスクをタスク領域に追加し、直ちにリターンします。 注呼び出しスレッドはタスク領域に加わる必要はありません。つまり、タスク領域外の任意の数のスレッドが、ブロックすることなく、タスク領域に作業を追加できます。警告タスク領域に追加されたタスクが、タスク領域のほかのタスクと並列に実行される保証はありません。 |
| template<F> void enqueue(const F&, priority_t) |
指定された優先度でタスクを追加します。その他は enqueue( const F& ) に似ています。 |
| template<F> void execute(F&)
template<F> void execute(const F&)
|
可能であれば、呼び出しスレッドはタスク領域で指定されたファンクターを実行し、タスク領域を離れて以前のタスク・スケジューラー状態に戻ります。 呼び出しスレッドがタスク領域に加わることができない場合は、ファンクターをタスクにラップし、タスク領域に追加して、OS カーネルの同期オブジェクトでタスクの完了を待機します。 注タスク領域外の任意の数のスレッドが作業を追加し、待機することができます。 ただし、タスクを実行できるのは、タスク領域で指定されている最大スレッド数までです。注タスク領域のワーカースレッドに対する要求が減り、ワーカーがタスク領域を離れ、その結果呼び出しスレッドが実行できるようになる場合があります。 |
| void wait_until_empty() |
タスク領域にあるすべての作業の完了を待機します。可能であれば、呼び出しスレッドは execute() と同じようにタスク領域に加わります。 警告このメソッドは、ほかのアプリケーション・スレッドによって追加された作業も含め、すべての作業を待機します。 |
| static int current_slot() |
戻り値: 現在のタスク領域で呼び出しスレッドに割り当てられたスロットのインデックス。 これは、例えば、タスク領域に入ろうとしているスレッドを特定のハードウェアに関連付けるために、task_scheduler_observer によって使用されます。 |