OpenMP でのループ途中脱出、是か非か
結論:仕様 3.0 ではループ途中の中断は禁止されている。
つまりループ途中の break や throw によるループ脱出は不可。
#pragma omp parallel for
for (int i = 0; i < 1000000; ++i) {
// no break nor throw (except catch it in this scope).
}
ループ本体で条件を都度確認して早期脱出する同僚コードを見て、それってダメだったよね? と朧げにあった記憶を再確認したのでメモ。
なおマイクロソフトの MSVC コンパイラーは仕様 2.0 に準拠しているとのこと。公式ページで OpenMP 2.0 仕様が確認できないため MSVC コンパイラーでのループ途中脱出の可否は不明。(とはいえ後続仕様で明確に禁じられているところで危険を冒す必要はないだろう)
参考: OpenMP
OpenMP は C コンパイラー拡張で、対象の for 文に #pragma omp parallel for などと前置して並列実行(による高速化)を指示する仕組み。
次のように pragma を付した for 文が、(PC が走らせられる数の)スレッドに振り分けられて実行される。(ループで配列の値の総和を取るなど結果をまとめる場合は排他制御用の追加指定が必要)
#pragma omp parallel for
for (int i = 0; i < 1000000; ++i) {
// 処理
}
参考: structured block
OpenMP の実行指定は「構造化ブロック」(もしくは OpenMP 構文)に適用される。仕様 3.0 用語集での構造化ブロックの定義は次のとおり:
structured block
For C/C++, an executable statement, possibly compound, with a single entry at the top and a single exit at the bottom, or an OpenMP construct.
For Fortran, a block of executable statements with a single entry at the top and a single exit at the bottom, or an OpenMP construct.
COMMENTS:
For all base languages,
• Access to the structured block must not be the result of a branch.
• The point of exit cannot be a branch out of the structured block.
For C/C++:
• The point of entry must not be a call to setjmp().
• longjmp() and throw() must not violate the entry/exit criteria.
• Calls to exit() are allowed in a structured block.
• An expression statement, iteration statement, selection statement, or try block is considered to be a structured block if the corresponding compound statement obtained by enclosing it in { and } would be a structured block.
For Fortran:
• STOP statements are allowed in a structured block.
実行可能な文、もしくは出入り口がひとつの複合文。コメント部にあるように条件分岐の結果であってはならず(if 文の帰結は不可)、条件分岐で脱出してもいけない(途中の break もダメ)。
また longjmp や throw は単一出入り口の基準を維持せねばならない──というわけで構造化ブロック内からの途中脱出は(exit を除いて)絶たれている。
余談
C++17 以降、 execution という並列実行が標準アルゴリズムの組み込みで利用可能になっている。 execution は規格標準。現時点で OpenMP を知らない人は、これを新たに学習するより execution を学んだほうが良いでしょう。
この記事が気に入ったらサポートをしてみませんか?