OpenMP の parallel for でローカルの値を外に持ち出す指定のひとつ lastprivate の意味を間違って覚えていると罠にハマる.last private であって last assigned private ではなかった.
下のようなプログラムを書いた.いつでも 2 が表示されて欲しい,つまり,lastprivate指定の変数は最後に代入された値を外に持ち出してくれると期待していた.
#include <omp.h> #include <iostream> struct mystruct { int f; mystruct() : f(-1) {} mystruct(int f) : f(f) {} }; int main(int argc, char *argv[]) { mystruct ms(1); #pragma omp parallel for lastprivate(ms) for(int i = 0; i < 4; i++) { if(i == 2) { mystruct msi(2); ms = msi; } } std::cout << ms.f << std::endl; return 0; }
が,実行してみると以下のような結果になった.
> OMP_NUM_THREADS=1 ./lastprivate 2 > OMP_NUM_THREADS=2 ./lastprivate 2 > OMP_NUM_THREADS=3 ./lastprivate 2 > OMP_NUM_THREADS=4 ./lastprivate -1
何かというと,lastprivate指定の変数は最後のプロセスの持つローカルな値をグローバルにコピーしてループを終了する,という仕組みであったと.確かにOpenMPの仕様にはそう書いてあるし,逐次実行時に最後に実行される反復で値を代入しない場合にはオブジェクトの初期値になっちゃうよ,とも書いてある.上のプログラムでの最終反復(i = 3)では変数 ms に値が代入されないため,その初期値(-1)になってループ終了と.
うーん,find みたいに最後に条件を満たすインデックスを探すとかいうループすらもOpenMPだと簡単に書けないのか… (FORTRAN なら MAX での reduction 指定ができるので可能だけど).
lastassignedprivate とかいうディレクティブの方が使い勝手が良いと思うのは気のせいだろうか? 変数についてフラグ一個持てば直ぐに実装できるのに… とりあえず OpenMP の reduction の制限がきつすぎるのが良くない.
- Newer: AWK - はじめ