スレッドプライベート変数のコピー
スレッドが持つプライベート変数を共有したくはないが、変数の値をコピーしたい状況があります。OpenMPではこの状況で使用できる指示句が2つ定義されています。それは、copyin
とcopyprivate
です。最初にcopyin
を解説します。
copyin
指示句で指定できる変数は、スレッドプライベート変数だけです。copyin
指示句を使用する場合、変数をスレッドプライベート変数に設定するthreadprivate
指示句と併用します。
copyin
指示句の使用法をサンプルプロジェクトCopyInSample
のコードで示します。
#include <stdio.h> #include <omp.h> /* グローバル変数をスレッドプライベート変数にする */ int x; #pragma omp threadprivate( x ) int main() { /* 静的変数をスレッドプライベート変数にする */ static int y; #pragma omp threadprivate( y ) /* 変数を初期化 */ x = 0; y = 0; #pragma omp parallel copyin( x, y ) { /* スレッドプライベート変数の初期値を表示 */ printf( "スレッド:%d\t Xの値 = %d, Yの値 = %d\n", omp_get_thread_num(), x, y ); /* 以下のプログラムは他のスレッドに影響を与えないが、ブロック外に影響を与える。 */ x = 10; y = 20; } /* 最終値を表示 */ printf( "【最終値】\t Xの値 = %d, Yの値 = %d\n\n", x, y ); return 0; }
copyin
指示句を使用すると、初期値をコピーすることができます。繰り返しになりますが、copyin
指示句は、スレッドプライベート変数のみ使用できます。また、静的変数もしくはグローバル変数でなくてはなりません。これは一見不自由な制限ですが、静的変数とグローバル変数は、並列処理においてバグを生み出すきっかけになるので、コードを安全なものにする機能だと言えます。この制限により変数のスコープが狭くなり、並列処理で発生するバグが自然と少なくなります。
次はcopyprivate
指示句を解説します。copyprivate
指示句を使用すると、あるスレッドの値をブロードキャストすることができます。文章では分かりにくいと思いますので、サンプルプロジェクトCopyPrivateSample
のコードを見てください。
#include <stdio.h> #include <omp.h> /* グローバル変数をスレッドプライベート変数にする */ int x; #pragma omp threadprivate( x ) int main() { /* 静的変数をスレッドプライベート変数にする */ static int y; #pragma omp threadprivate( y ) /* 変数を初期化 */ x = 0; y = 0; #pragma omp parallel num_threads( 10 ) copyin( x, y ) { /* 他のスレッドに存在するプライベート変数の値を変更 */ #pragma omp single copyprivate( x, y ) { x = 100; y = 200; printf( "スレッド%dが値を変更しました\t Xの値 = %d, Yの値 = %d\n", omp_get_thread_num(), x, y ); } /* 現在の変数の値を表示 */ x *= ( omp_get_thread_num() + 1 ); y *= ( omp_get_thread_num() + 1 ); printf( "スレッド:%d\t Xの値 = %d, Yの値 = %d\n", omp_get_thread_num(), x, y ); } /* 最終値を表示 */ printf( "【最終値】\t Xの値 = %d, Yの値 = %d\n\n", x, y ); return 0; }
このコードを実行すると、copyprivate
指示句で指定されたブロック内のコードが、他のスレッドにも反映されているのが確認できます。
copyprivate
指示句は、single構文でのみ指定でき、ブロードキャストされるタイミングに注意せねばならないので、使用するべき状況が限られています。使用する際には十分に注意してください。
これで、スレッドプライベート変数のコピーについての解説は終わりです。次項では、並列リダクションについて解説します。