task_arena
[scheduler.task_arena]
明示的なユーザー管理のタスク・スケジューラーのアリーナを表すクラス。
// <oneapi/tbb/task_arena.h> ヘッダーで定義
namespace oneapi {
namespace tbb {
class task_arena {
public:
static const int automatic = /* unspecified */;
static const int not_initialized = /* unspecified */;
enum class priority : /* unspecified type */ {
low = /* unspecified */,
normal = /* unspecified */,
high = /* unspecified */
};
struct constraints {
constraints(numa_node_id numa_node_ = task_arena::automatic,
int max_concurrency_ = task_arena::automatic);
constraints& set_numa_id(numa_node_id id);
constraints& set_max_concurrency(int maximal_concurrency);
constraints& set_core_type(core_type_id id);
constraints& set_max_threads_per_core(int threads_number);
numa_node_id numa_id = task_arena::automatic;
int max_concurrency = task_arena::automatic;
core_type_id core_type = task_arena::automatic;
int max_threads_per_core = task_arena::automatic;
};
task_arena(int max_concurrency = automatic, unsigned reserved_for_masters = 1,
priority a_priority = priority::normal);
task_arena(constraints a_constraints, unsigned reserved_for_masters = 1,
priority a_priority = priority::normal);
task_arena(const task_arena &s);
explicit task_arena(oneapi::tbb::attach);
~task_arena();
void initialize();
void initialize(int max_concurrency, unsigned reserved_for_masters = 1,
priority a_priority = priority::normal);
void initialize(constraints a_constraints, unsigned reserved_for_masters = 1,
priority a_priority = priority::normal);
void initialize(oneapi::tbb::attach);
void terminate();
bool is_active() const;
int max_concurrency() const;
template<typename F> auto execute(F&& f) -> decltype(f());
template<typename F> void enqueue(F&& f);
void enqueue(task_handle&& h);
};
} // namespace tbb
} // namespace oneapi
task_arena
クラスは、スレッドがタスクを共有および実行可能な場所を示します。
task_arena
のタスクを同時に実行するスレッド数は平行レベルにより制限されます。
明示的な task_arena
の外部で並列構造を呼び出すユーザースレッドは、 呼び出し元のスレッドに関連する暗黙的なタスクアリーナを表現するオブジェクトを使用します。
あるアリーナにスポーンまたは追加されたタスクは、ほかのアリーナでは実行できません。
それぞれの task_arena
は priority
を持ちます。優先順位の高い task_arena
のタスクは、順位の低い task_arena
のタスクよりも実行が優先されます。
注
task_arena
コンストラクターは、内部タスクアリーナの表現オブジェクトを作成しません。「アタッチ」コンストラクターはすでに存在している可能性があります。さもなければ、明示的にtask_arena::initialize
を呼び出すか、初回の使用時に遅延して作成されます。
メンバーのタイプと定数
- static const int automatic
max_concurrency
が特定のコンストラクターに渡されると、アリーナの同時実行性はハードウェア構成に基づいて自動的に設定されます。
- static const int not_initialized
メソッドまたは関数から返された場合、アクティブな
task_arena
がないか、task_arena
オブジェクトがまだ初期化されていないことを示します。
- enum priority::low
コンストラクターまたは
initialize
メソッドに渡されると、初期化されたtask_arena
の優先順位は低くなります。
- enum priority::normal
コンストラクターまたは
initialize
メソッドに渡されると、初期化されたtask_arena
の優先順位は通常になります。
- enum priority::high
コンストラクターまたは
initialize
メソッドに渡されると、初期化されたtask_arena
の優先順位は髙くなります。
- struct constraints
task_arena
内部のスレッドに適用される制限を表現します。C++20 以降では、このクラスは指定する初期化をサポートする集合体タイプである必要があります。
- numa_node_id constraints::numa_id
NUMA ノードを一意に識別する整数論理インデックス。非自動値に設定されている場合、この NUMA ノードはアリーナ内のすべてのスレッドで優先されると見なされます。
注
NUMA ノード ID は、tbb::info::numa_nodes() を介して取得された場合に有効となります。
- int constraints::max_concurrency
task_arena
内で同時に処理するワークに参加できるスレッドの最大数。
- core_type_id constraints::core_type
コアタイプを一意に識別する整数論理インデックス。非自動値に設定されている場合、この NUMA ノードはアリーナ内のすべてのスレッドで優先されると見なされます。
注
コアタイプ ID は、
tbb::info::core_types()
を介して取得された場合に有効になります。
- int constraints::max_threads_per_core
1 つのコアに同時にスケジュールできるスレッドの最大数。
- constraints::constraints(numa_node_id numa_node_ = task_arena::automatic, int max_concurrency_ = task_arena::automatic)
指定された numa_id と max_concurrency の設定を使用して、制約オブジェクトを構築します。
注
指定された初期化をサポートするため、C++20 以降ではこのコンストラクターは除外されます。代わりに集約型の初期化が使用されます。
- constraints &constraints::set_numa_id(numa_node_id id)
numa_id を指定された
id
に設定します。更新された制約オブジェクトの参照を返します。
- constraints &constraints::set_max_concurrency(int maximal_concurrency)
max_concurrency を指定された
maximal_concurrency
に設定します。更新された制約オブジェクトの参照を返します。
- constraints &constraints::set_core_type(core_type_id id)
core_type を指定された
id
に設定します。更新された制約オブジェクトの参照を返します。
- constraints &constraints::set_max_threads_per_core(int threads_number)
max_threads_per_core を指定された
threads_number
に設定します。更新された制約オブジェクトの参照を返します。
メンバー関数
- task_arena(int max_concurrency = automatic, unsigned reserved_for_masters = 1, priority a_priority = priority::normal)
特定の同時実行制限 (
max_concurrency
) と優先順位 (a_priority
) でtask_arena
を作成します。制限の一部は、reserved_for_masters
を使用してアプリケーション・スレッド向けに予約できます。予約数は制限を超えることはできません。警告
max_concurrency
およびreserved_for_masters
が共に等しく 1 以上に設定されている場合、oneTBB のワーカースレッドはアリーナに参加することはありません。その結果、これらのアリーナではキューに投入されたタスクの実行は保証されません。ワーカースレッドなしに設定されたアリーナでtask_arena::enqueue()
を使用しないでください。
- task_arena(constraints a_constraints, unsigned reserved_for_masters = 1, priority a_priority = priority::normal)
特定の制限 (
a_constraints
) と優先順位 (a_priority
) でtask_arena
を作成します。制限の一部は、reserved_for_masters
を使用してアプリケーション・スレッド向けに予約できます。予約数は、constraints
で指定された同時実行の制限を超えることはできません。警告
constraints::max_concurrency
およびreserved_for_masters
が共に等しく 1 以上に設定されている場合、oneTBB のワーカースレッドはアリーナに参加することはありません。その結果、これらのアリーナではキューに投入されたタスクの実行は保証されません。ワーカースレッドなしに設定されたアリーナでtask_arena::enqueue()
を使用しないでください。constraints::numa_node
が指定されていると、アリーナを実行するすべてのスレッドは、対応する NUMA ノードに自動的にピニングされます。
- task_arena(const task_arena&)
別の
task_arena
インスタンスから設定をコピーします。
- explicit task_arena(oneapi::tbb::attach)
呼び出しスレッドで使用されている内部タスクアリーナ表現に接続される
task_arena
のインスタンスを作成します。アリーナがまだ存在しない場合、デフォルト・パラメーターでtask_arena
を作成します。注
他のコンストラクターとは異なり、すでに存在する領域に接続したとき新しい
task_arena
は自動的に初期化されます。
- ~task_arena()
task_arena
インスタンスを破棄しますが、破棄はこのtask_arena
内のタスクの実行と同期されない場合があります。これは、task_arena
インスタンスに関連する内部タスクアリーナ表現を遅延して破棄できることを意味します。ほかのメソッドを同時に呼び出した場合、スレッドセーフではありません。
- void initialize()
内部タスクアリーナ表現を初期化します。
注
initialize
が呼び出されるとアリーナのパラメーターは固定され、変更することはできません。
- void initialize(int max_concurrency, unsigned reserved_for_masters = 1, priority a_priority = priority::normal)
上記と同様ですが、以前のアリーナ・パラメーターをオーバーライドします。
- void initialize(constraints a_constraints, unsigned reserved_for_masters = 1, priority a_priority = priority::normal)
上記と同様。
- void initialize(oneapi::tbb::attach)
呼び出しスレッドで現在使用されている内部タスクアリーナ表現が存在する場合、メソッドはアリーナ・パラメーターを無視して
task_arena
をその内部タスクアリーナ表現に接続します。すでに初期化されているtask_arena
に対して呼び出された場合、メソッドは効果がありません。
- void terminate()
task_arena オブジェクトを破棄せずに内部タスクアリーナ表現への参照を削除します。この task_arena オブジェクトは再利用できます。他のメソッドの同時に呼び出しに対しスレッドセーフではありません。
- bool is_active() const
task_arena
が初期化されている場合はtrue
を返し、それ以外はfalse
を返します。
- int max_concurrency() const
task_arena
の並行レベルを返します。task_arena
を初期化する必要がなく、初期化を実行しません。
- template<F>
void enqueue(F &&f) 指定されたファンクターを処理するため、タスクを
task_arena
に追加し直ちにリターンします。F
タイプは、[function.objects] ISO C++ 標準の Function Objects の要件を満たしている必要があります。タスクの完了を明示的に待機するスレッドがない場合でも、タスクはワーカースレッドで実行されるようにスケジュールされます。ワーカースレッドの総数がセロである場合、キューに投入されたタスクを実行する特殊なワーカースレッドが生成されます。注
メソッドでは、呼び出し元のスレッドはアリーナに参加する必要はありません。つまり、アリーナ外の任意の数のスレッドが、ブロックすることなくアリーナにワークを送信できます。
警告
アリーナのキューに投入されたタスクが、ほかのタスクと同時に実行される保証はありません。
警告
例外がスローされ、ファンクターでキャッチされない場合の動作は未定義です。
- template<F>
auto execute(F &&f) -> decltype(f()) 指定されるファンクターを
task_arena
で実行し、ファンクターの戻り値を返します。F
タイプは、[function.objects] ISO C++ 標準の Function Objects の要件を満たしている必要があります。呼び出しスレッドは、可能であれば
task_arena
に参加してファンクターを実行します。リターンすると、以前のタスク・スケジューラーの状態と浮動小数点設定を復元します。task_arena
へジョインできない場合、ファンクターをタスクにラップしてアリーナのキューに追加し、OS カーネルの同期オブジェクトを使用してジョインする機会を待ち、タスクの完了後に終了します。ファンクターでスローされた例外はキャプチャーされ、
execute
から再度スローされます。注
アリーナ外の任意の数のスレッドがアリーナにワークを送信できますがブロックされる可能性があります。ただし、ワークを実行できるのは、アリーナで指定されている最大スレッド数までです。
- void enqueue(task_handle &&h)
h
が所有するタスクを処理するためtask_arena
にエンキューします。この関数の動作は、パラメーター・タイプを除き、汎用バージョン (
template<typename F> void task_arena::enqueue(F&& f)
) と同じです。注
未定義の動作を避けるため、
h
は空であってはなりません。
例
この例は、task_arena
の NUMA サポート API を示します。構築された task_arena
は、対応する NUMA ノードに固定されます。
#include "oneapi/tbb/task_group.h"
#include "oneapi/tbb/task_arena.h"
#include <vector>
int main() {
std::vector<oneapi::tbb::numa_node_id> numa_nodes = oneapi::tbb::info::numa_nodes();
std::vector<oneapi::tbb::task_arena> arenas(numa_nodes.size());
std::vector<oneapi::tbb::task_group> task_groups(numa_nodes.size());
for (int i = 0; i < numa_nodes.size(); i++) {
arenas[i].initialize(oneapi::tbb::task_arena::constraints(numa_nodes[i]));
}
for (int i = 0; i < numa_nodes.size(); i++) {
arenas[i].execute([&task_groups, i] {
task_groups[i].run([] {
/* executed by the thread pinned to specified NUMA node */
});
});
}
for (int i = 0; i < numa_nodes.size(); i++) {
arenas[i].execute([&task_groups, i] {
task_groups[i].wait();
});
}
return 0;
}
参照: