task_arena クラス

概要

明示的なユーザー管理タスク・スケジューラー領域の表現。

構文

class task_arena;

ヘッダー

#include "tbb/task_arena.h"

説明

task_arena クラスは、複数のスレッド (スレッド数は最大並列レベルにより制限される) がタスクを共有し実行する、内部タスク・スケジューラー・オブジェクトを表します。

task_arena の並列レベルは分離されており、以前の task_scheduler_init 仕様の影響を受けません。

プロセスで利用可能なスレッド数の合計は、次のいずれか大きいほうにより制限されます: マシンのデフォルトのスレッド数または最初のタスク・スケジューラーの初期化で指定された値。そのため、task_arena に割り当てられるスレッド数は、並列レベルに関係なく、最大値を超えることはありません。

指定された並列レベルが許容最大値より小さい場合でも、task_arena に割り当てられるワーカー数が少なかったり、指定されたスレッド数が割り当てられないことがあります。

タスク・スケジューラーを明示的または暗黙的に初期化する各ユーザースレッドには、暗黙の内部タスク領域オブジェクトが含まれます。タスク領域にスポーンまたは追加されたタスクは、ほかのタスク領域では実行できません。

task_arena のインスタンスは、内部表現への参照を作成して保持しますが、その存続期間を完全には管理しません。内部表現は、タスクが含まれるか、ほかのワーカースレッドが参照している間は破棄できません。

task_arena コンストラクターは、内部タスク領域オブジェクトを作成しません。初回使用時に遅れて作成されるか、または明示的に task_arena::initialize を呼び出して作成されます。

インテル® TBB は、task_arena で表された明示的な領域オブジェクトを処理する場合、現在のスレッドに対して暗黙の領域オブジェクトを割り当てません。task_scheduler_init を使用する現在のスレッドの後続の初期化では、指定されたスレッド数に関係なくデフォルトの設定が使用されます。これは、インテル® TBB タスク・スケジューラーに関連するメソッドの呼び出しが、暗黙の領域オブジェクトの作成を含め、現在のスレッドのタスク・スケジューラーを初期化していた、以前のバージョンのインテル® TBB との互換性を提供します。

メンバー

namespace tbb {
class task_arena {
public:
    static const int automatic = implementation-defined;
    static int current_thread_index();
    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);
};
}

サンプル

次のサンプルは、同時に 2 つの paralel_for ループを実行します。1 つはスケーラブルで、もう 1 つはスケーラブルではありません。スケーラブルでないループは最大 2 スレッドに制限されるため、ほとんどのスレッドはスケーラブルなループに使用できます。特定のタスクのサブセットを待機するには、task_group を使用します。

tbb::task_scheduler_init def_init; // スレッドのデフォルトの番号を使用
tbb::task_arena limited(2);// この領域では最大 2 スレッドのみ
tbb::task_group tg;

limited.execute([&]{ // 最大 2 つのスレッドを使用
    tg.run([]{ // タスクグループで実行
        tbb::parallel_for(1, N, unscalable_work());
    });
}); 

// 別のジョブを上記のループと並列に実行
// スレッドのデフォルトの番号を使用可能:
tbb::parallel_for(1, M, scalable_work());

// execute() の内側でタスクグループを
// 待つようにする
// このタスクグループのタスクのみを待つ
limited.execute([&]{ tg.wait(); });

次の表は、このテンプレート・クラスのメンバーの詳細な情報を提供します。

メンバー 説明
task_arena(int max_concurrency = automatic, unsigned reserved_for_masters = 1)

特定の並列レベルで、一部がアプリケーション・スレッド向けに予約された task_arena を作成します。

インテル® TBB 4.3 の task_arena の実装において、reserved_for_masters の有効な値は 0 と 1 のみです。

static const int automatic

max_concurrency として上記のコンストラクターに渡されると、ハードウェア構成に基づいてタスク領域の並列性が自動で設定されます。

task_arena(const task_arena&)

別の task_arena インスタンスから設定をコピーします。

~task_arena()

内部タスク領域表現への参照を削除し、task_arena() のインスタンスを破棄します。ほかのメソッドを同時に呼び出した場合、スレッドセーフではありません。

void initialize();

void initialize(int max_concurrency, unsigned reserved_for_masters = 1);

内部タスク領域表現の初期化を実行します。引数が指定されている場合、以前の並列化の設定をオーバーライドします。すでに初期化されているタスク領域に対して呼び出された場合、効果はありません。

initialize の呼び出しの後、タスク領域の並列性は固定され、変更することはできません。
void terminate() task_arena オブジェクトを破棄しないで内部タスク領域表現への参照を削除します。task_arena オブジェクトは再利用できます。ほかのメソッドを同時に呼び出した場合、スレッドセーフではありません。
bool is_active() タスク領域が初期化された場合は true を返し、その他の場合は false を返します。
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&)

可能であれば、呼び出しスレッドはタスク領域で指定されたファンクターを実行し、タスク領域を離れて以前のタスク・スケジューラー状態と浮動小数点設定にジョインします。

警告

すでに領域内にあるスレッドが execute への入れ子の呼び出しを行うと、領域のキューに入れられた作業を処理できないことがあります。

呼び出しスレッドがタスク領域にジョインすることができない場合は、ファンクターをタスクにラップし、タスク領域に追加し、OS カーネルの同期オブジェクトを用いてジョインする機会を待機し、タスクの完了後に終了します。

警告

領域 (B) を (B.execute([]{ A.execute([]{ B.execute(f); }); }); のように) 間接的に 2 回ジョインすると、この領域の有効な並列性が減り、デッドロックを引き起こすことがあります。

タスク領域外の任意の数のスレッドが作業を追加し、待機することができます。ただし、作業を実行できるのは、タスク領域で指定されている最大スレッド数までです。

execute により、タスク領域のワーカースレッドに対する要求が減り、ワーカーがタスク領域を離れ、その結果呼び出しスレッドが実行できるようになる場合があります。

ファンクターでスローされた例外はキャプチャーされ、execute から再スローされます。正しい例外の伝播が利用できないか無効な場合、例外は (同じスレッドの例外でも) tbb::captured_exception にラップされます。
static int current_thread_index()

戻り値: 呼び出しスレッドで現在使用されているタスク領域のスレッド・インデックス。スレッドがまだタスク・スケジューラーを初期化していない場合は -1。スレッド・インデックスは、0 から領域の並列レベルまでの整数です。スレッド・インデックスは、領域にジョインしている間はアプリケーション (マスター) スレッドとワーカースレッドの両方に割り当てられ、領域を離れるまで保持されます。領域を共有するスレッドのインデックスは一意です (つまり、領域内の 2 つのスレッドが同じインデックスを持つことはありません) が、必ずしも連続していません。

タスクを実行しない場合、スレッドはいつでも領域を離れることがあるため、スレッドのインデックスは、同じタスクグループやアルゴリズムに属している 2 つのタスク間でも変わることがあります。

異なる領域を使用するスレッドは、同じ現在のインデックス値を持つことがあります。

execute() に入れ子の領域をジョインすると、リターン時に戻される外側の領域のインデックスが保存され、現在のインデックス値が変更されることがあります。

この方法は、例えば、タスク領域に入ろうとしているスレッドを特定のハードウェアに関連付けるために、task_scheduler_observer のプレビュー機能によって使用されます。

関連情報