付録 B: その他のスレッドパッケージとの併用#
正しい相互運用性#
oneTBB は他のスレッドパッケージでも使用できます。追加の作業は必要ありません。
以下は、外側のループを OpenMP* で並列化し、内側のループを oneTBB で並列化する例です。
int M, N;
struct InnerBody {
int i;
void operator()(tbb::blocked_range<int> const& r) const {
for (auto j = r.begin(); j != r.end(); ++j) {
// (i, j) 要素のワークを実行
}
}
};
void TBB_NestedInOpenMP() {
#pragma omp parallel
{
#pragma omp for
for(int i = 0; i < M; ++i) {
tbb::parallel_for(tbb::blocked_range<int>(0, N, 10), InnerBody(i));
}
}
}#pragma omp parallel は、OpenMP* にスレッドのチームを作成するように指示します。各スレッドは、ディレクティブに関連付けられたコードブロックのステートメントを実行します。
#pragma omp for は、コンパイラーが次のループの反復を既存のスレッドチーム内のスレッド間で分散し、ループ本体の並列実行を可能にすることを示します。
POSIX* スレッドの同様の例を参照してください。
int M, N;
struct InnerBody {
int i;
void operator()(tbb::blocked_range<int> const& r) const {
for (auto j = r.begin(); j != r.end(); ++j) {
// (i, j) 要素のワークを実行
}
}
};
void* OuterLoopIteration(void* args) {
int i = reinterpret_cast<intptr_t>(args);
tbb::parallel_for(tbb::blocked_range<int>(0, N, 10), InnerBody(i));
return nullptr;
}
void TBB_NestedInPThreads() {
std::vector<pthread_t> id(M);
// 外側のループの繰り返しごとにスレッドを作成
for(int i = 0; i < M; ++i) {
std::intptr_t arg = i;
pthread_create(&id[i], NULL, OuterLoopIteration, (void*)arg);
}
// 外側のループスレッドが終了するまで待機
for(int i = 0; i < M; ++i)
pthread_join(id[i], NULL);
}過剰な CPU の使用を避ける#
実行の正当性に影響することなく、oneTBB を他のスレッドパッケージと安全に使用できますが、複数のスレッドプールから多数のスレッドを同時に実行すると、オーバーサブスクリプションが発生する可能性があります。これにより、システムリソースが過剰に使用され、実行パフォーマンスに影響することになります。
ネストされた並列処理を使用した前述の例で、並列ループ内で OpenMP* 並列領域が実行される場合を考えてみましょう。
int M, N;
void InnerBody(int i, int j) {
// (i, j) 要素のワークを実行
}
void OpenMP_NestedInTBB() {
tbb::parallel_for(0, M, [&](int i) {
#pragma omp parallel for
for(int j = 0; j < N; ++j) {
InnerBody(i, j);
}
});
}OpenMP* 並列領域のセマンティクスにより、この並列ランタイムの構成では、同時に実行されるスレッドの数が 2 乗になる可能性があります。このようなオーバーサブスクリプションによりパフォーマンスが低下する可能性があります。
oneTBB は、スレッド・コンポーザビリティー・マネージャー (TCM) を使用してこの問題を解決します。これは、異なるスレッドランタイム間の連携を向上させる実験的な CPU リソースの調整レイヤーです。
デフォルトでは、TCM は無効になっています。有効にするには、TCM_ENABLE 環境変数を 1 に設定します。意図どおりに動作することを確認するには、アプリケーションを実行する前に TCM_VERSION 環境変数を 1 に設定し、TCM: で始まる行の出力を確認します。TCM: TCM_ENABLE 1 の行は、スレッド・コンポーザビリティー・マネージャーがアクティブであることを示します。
出力例。
TCM: VERSION 1.3.0
<...>
TCM: TCM_ENABLE 1インテル® DPC++/C++ コンパイラーの OpenMP* 実装と併用すると、TCM により、上記と同様のシナリオで過剰なスレッドの同時スケジュールを回避できます。
oneTBB GitHub Issues または Discussions を通じて、スレッド・コンポーザビリティー・マネージャーに関するフィードバックを送信したり、質問したりしてください。
注
CPU リソースの使用を調整するには、スレッド・コンポーザビリティー・マネージャーのサポートが必要です。最適な調整のため、アプリケーション内の各スレッドパッケージが TCM と統合されていることを確認してください。
関連情報