タスクは、task 構文が使用されているルーチン (ホストルーチン) のスタック上のデータを参照することがあります。タスクの実行は次の暗黙または明示バリアまで延期されることがあるため、ホストルーチンのスタックがポップされ、スタックデータが上書きされたあとでタスクが実行される可能性があり、それによって、タスクが参照したスタックデータが破棄されます。
このセクションの 2 つの例に示すように、必要な同期処理を挿入して、タスクが変数を参照したときに、変数が確実にスタック上にあるようにしておいてください。
Example 4–8 では、i が task 構文で shared になるように指定されるため、タスクは、work() ルーチンのスタック上に割り当てられている i のコピーにアクセスします。
タスクの実行は延期されることがあるため、タスクは main() の並列領域の終わりにある暗黙バリアで、work() ルーチンの復帰後に実行されます。その時点で、タスクが i を参照すると、そのときにたまたまスタック上にあった値にアクセスしてしまいます。
正しい結果が得られるよう、タスクが完了する前に work() が復帰しないようにしてください。そのためには、Example 4–9 に示すように、taskwait ディレクティブを task 構文のあとに挿入します。あるいは、task 構文で、i を shared ではなく、firstprivate になるように指定することもできます。
使用例 4-8 スタックデータ: 正しくない参照#include <stdio.h> #include <omp.h> void work() { int i; i = 10; #pragma omp task shared(i) { #pragma omp critical printf("In Task, i = %d\n",i); } } int main(int argc, char** argv) { omp_set_num_threads(8); omp_set_dynamic(0); #pragma omp parallel { work(); } }使用例 4-9 スタックデータ: 修正された参照
#include <stdio.h> #include <omp.h> void work() { int i; i = 10; #pragma omp task shared(i) { #pragma omp critical printf("In Task, i = %d\n",i); } /* Use TASKWAIT for synchronization. */ #pragma omp taskwait } int main(int argc, char** argv) { omp_set_num_threads(8); omp_set_dynamic(0); #pragma omp parallel { work(); } }
次の例では、task 構文中の j が sections 構文中の j を参照しています。このため、タスクは firstprivate のコピーである sections 構文中の j にアクセスします。これは、Oracle Solaris Studio では、sections 構文のアウトラインルーチンのスタック上のローカル変数です。
タスクの実行は延期されることがあり、タスクが sections 領域の終わりにある暗黙バリアで、sections 構文のアウトラインルーチンの終了後に実行されることがあります。そのため、タスクが j を参照すると、スタック上の不確定の値にアクセスしてしまいます。
正しい結果を得るためには、Example 4–11 に示すように、taskwait ディレクティブを task 構文のあとに挿入して、sections 領域がその暗黙バリアに到達する前にタスクが実行されるようにしてください。あるいは、task 構文で、j を shared ではなく firstprivate になるように指定することもできます。
使用例 4-10 sections データ: 正しくない参照#include <stdio.h> #include <omp.h> int main(int argc, char** argv) { omp_set_num_threads(2); omp_set_dynamic(0); int j=100; #pragma omp parallel shared(j) { #pragma omp sections firstprivate(j) { #pragma omp section { #pragma omp task shared(j) { #pragma omp critical printf("In Task, j = %d\n",j); } } } /* Implicit barrier for sections */ } /* Implicit barrier for parallel */ printf("After parallel, j = %d\n",j); }使用例 4-11 sections データ: 修正された参照
#include <stdio.h> #include <omp.h> int main(int argc, char** argv) { omp_set_num_threads(2); omp_set_dynamic(0); int j=100; #pragma omp parallel shared(j) { #pragma omp sections firstprivate(j) { #pragma omp section { #pragma omp task shared(j) { #pragma omp critical printf("In Task, j = %d\n",j); } /* Use TASKWAIT for synchronization. */ #pragma omp taskwait } } /* Implicit barrier for sections */ }/* Implicit barrier for parallel */ printf("After parallel, j = %d\n",j); }