ループが複雑な制御フローを持つことがあります。このような状況でインテル® oneAPI スレッディング・ビルディング・ブロック (oneTBB) を使用する場合、単純なループを扱う場合よりも多くのことが求められます。タスク本体では、アノテーション・サイト内で定義されている自動変数にアクセスしてはなりません。このような変数は、タスクの実行前または実行中に破棄される可能性があるためです。次のシリアルコードについて考えてみます。
extern char a[];
int previousEnd = -1;
ANNOTATE_SITE_BEGIN(sitename);
for (int i=0; i<=100; i++) {
if (!a[i] || i==100) {
ANNOTATE_TASK_BEGIN(do_something);
DoSomething(previousEnd+1,i);
ANNOTATE_TASK_END();
previousEnd=i;
}
}
ANNOTATE_SITE_END();
複雑な制御を持つループは本質的にシーケンシャルであるため、一般に単純なカウント付きループのほうが複雑な反復制御を持つループよりもスケーラビリティーが優れています。可能であれば、単純なカウント付きのループへの書き換えを検討してください。
上記のループを並列化する 1 つの手法として、oneTBB の task_group 機能を使用することができます。
#include <tbb/tbb.h>
...
extern char a[];
int previousEnd = -1;
task_group g;
for (int i=0; i<=100; i++) {
if (!a[i] || i==100) {
g.run([=]{DoSomething(previousEnd+1,i);}
previousEnd=i;
}
}
g.wait(); // グループ内のすべてのタスクの完了を待機
式がファンクターを構成する場合、i と previousEnd の値を取得することが重要であるため、値によってキャプチャーするラムダ式 [=] を使用します。これは、previousEnd と i の値が後で変化するためです。
tbb::task_group に関する詳細は、oneTBB のドキュメントを参照してください。