OpenMP 入門

ナビゲーション:前へ   上へ   次へ

5 データ共有属性の指定について

OpenMPの並列領域においては前述のとおり複数のスレッドにより実行が行われますが、 その際に構造化ブロック内に出現する変数はOpenMPが定めるルールにより、 スレッド間で共有されたりされなかったりします。 細かいルールについては本ドキュメントでは説明しませんが、 おおよそのルールとして、doループの反復制御変数は共有されず(private)、 それ以外は共有される(shared)と考えることができます。

またデータ共有属性をユーザが明示的に指定することも可能です。

5.1 データ共有属性を指定する

変数を共有するかどうかを明示的に指定する場合には該当する構文の指示節として指定します。
例)
!$omp parallel shared(a,x), private(i)
上記例は変数 a 及び x を共有し、変数 i を共有しない事を指定しています。

以下に主なデータ共有属性指示節を示します。

shared(list)
listで示される変数が共有される事を示します。すべてのスレッドで同じデータが共有されます。
private(list)
listで示される変数がスレッド毎に用意されることを示します。 このスレッド毎に用意される変数は、 構文開始時に(もともとの変数値に関わらず)全く新たに未定義の状態で作成されます。
firstprivate(list)
listで示される変数がスレッド毎に用意されることを示します。 このスレッド毎に用意される変数は、privateの場合と異なり、 構文開始時にもともとの変数値で初期化されます。
default(private|firstprivate|shared|none)
データ共有属性の指定を行わなかった変数のdefaultの属性を指定します。 noneを指定した場合、構文内で使われるすべての変数のデータ共有属性を明示的に指定する必要があります。
reduction(operator|intrinsic_procedure_name:list)
listで指定される変数をoperatorで指定される演算もしくはintrinsic_procedure_nameで指定される手続きで集計します。

以下にいくつかのdefaultを指定する場合の記述例を示します。

変数iとjのみをprivateとし、残り全てをsharedとして指定する例)
!$omp parallel default(shared), private(i,j)

全てのデータ共有属性を明示する事と、変数iをprivate、変数xをsharedとして指定する例)
!$omp parallel default(none), private(i), shared(x)

データ共有属性の指定が行える主なOpenMP指示構文は以下の通りです。

  • parallel指示構文
  • do指示構文
  • section指示構文

ここで以下のコードを考えます。

program dataSharing
  implicit none
  integer i, j
  integer,parameter :: N = 10000
  integer,allocatable :: a(:)
  allocate(a(N))
  a = 0
!$omp parallel
!$omp do
  do i=1, 10000
    j = i
    a(j) = i
  end do
!$omp end do
!$omp end parallel
  print *, sum(a)
end program
このコードをOpenMPのオプションを指定せずにコンパイル・実行すると 1+2+3+4+ ... 10000 の結果である 50005000が以下のように出力されます。
実行例)
 50005000
次に同じコードをOpenMPのオプションを指定してコンパイルし、 4スレッドで実行した場合の出力例をいくつか示します。
実行例その1)
 50005000

実行例その2)
 49979275

実行例その3)
 49995341
実行例その1のように正しい結果が得られる場合がある一方で、 実行例その2やその3のように誤った結果が得られる場合もある状況となってしまいました。

上記のプログラム例では構造化ブロック内の変数 j が各スレッド間で共有されています。(shared属性) そのため、j = i の処理と a(j) = i の処理の間に、 他のスレッドがjの値を書き換えてしまう状況がありえるために誤った結果が出力されています。

上記プログラムを正しく動くように修正するには

!$omp parallel
!$omp parallel private(j)
と書き換えるかもしくは
!$omp do
!$omp do private(j)
と書き換えます。

5.2 ☆演習課題:データ共有属性

下記に示すプログラムは現状では正しく動きません。 OpenMPの共有属性を明示的に指定して正しく動くようにして下さい。
[課題のコード]

program kadaiDataSharing
  implicit none
  integer i, j
  integer,parameter :: N=10000
  integer,allocatable :: a(:), b(:)
  allocate( a(N), b(N) )
  a = (/(i,i=1,N)/)
  b = 0
!$omp parallel
!$omp do
  do i=1, N
    j = N - i + 1
    b(j) = a(i)
  end do
!$omp end do
!$omp end parallel
  print *, sum(a), "=", sum(b)
end program
[想定される正しい実行出力例(何回実行しても右辺と左辺が同じ)]
 50005000 = 50005000
[ヒント]
明示的に変数の共有属性を指定します。
解答例1(最低限の指定を行う例):kadaiDataSharing.f90
解答例2(全て明示的に指定する例):kadaiDataSharingAll.f90


ナビゲーション:前へ   上へ   次へ
関連情報
ご案内
© 日本ニューメリカルアルゴリズムズグループ株式会社 2025
Privacy Policy  /  Trademarks