スレッドプライベート変数のコピー
スレッドが持つプライベート変数を共有したくはないが、変数の値をコピーしたい状況があります。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構文でのみ指定でき、ブロードキャストされるタイミングに注意せねばならないので、使用するべき状況が限られています。使用する際には十分に注意してください。
これで、スレッドプライベート変数のコピーについての解説は終わりです。次項では、並列リダクションについて解説します。