omp parallel でスレッド並列化を行う場合には
が重要である。
例えば以下のようなコードは OpenMP 有効時に結果の再現性を損う可能性がある。
!$omp parallel
do ntrc = ntrc_strt, numtrc
if ( trim(adv_scheme(ntrc)%name)/="som" .and. trim(adv_scheme(ntrc)%name)/="ppm" ) then
trczadvtmp(1:imu, 1:jmu, ntrc) = 0.d0
!$omp do private(i,k,kd,wt)
do j = 2, jmu
do i = 2, imu
k = ktbtm(i, j) - texnbbl(i,j)
kd = km+1-kbbl
wt = sign(vupp-.5D0, wlwl_total(i,j,k))
trczadvtmp(i,j,ntrc) = atexl(i,j,kd)&
& * (wlwl_total(i,j,k)&
& *((.5D0-wt)*trcbl(i,j,k,ntrc)&
& +(.5D0+wt)*trcbl(i,j,kd,ntrc)))
end do
end do
end if
end do
!$omp end parallel
上記コードでは、
ことが問題である。 つまり、trczadvtmp の0埋め作業が全てのスレッドで終了する前に、doループでのtrczadvtmp計算が開始される場合がある。 正しく計算された trczadvtmp が、再度0埋めされる場合があり、これによって結果の再現性が損われてしまう。
4行目と5行目の間に !omp barrier を挿入してスレッド間同期をとれば、結果の再現性は確保できる。 しかし、今回のケースでは、無用なトラブルを避けるためにも、single 指示文を用いてスレッド競合を排した以下のような実装が好ましい。
!$omp parallel
do ntrc = ntrc_strt, numtrc
if ( trim(adv_scheme(ntrc)%name)/="som" .and. trim(adv_scheme(ntrc)%name)/="ppm" ) then
!$omp single
trczadvtmp(1:imu, 1, ntrc) = 0.d0
trczadvtmp(1, 2:jmu, ntrc) = 0.d0
!$omp end single
!$omp do private(i,k,kd,wt)
do j = 2, jmu
do i = 2, imu
k = ktbtm(i, j) - texnbbl(i,j)
kd = km+1-kbbl
wt = sign(vupp-.5D0, wlwl_total(i,j,k))
trczadvtmp(i,j,ntrc) = atexl(i,j,kd)&
& * (wlwl_total(i,j,k)&
& *((.5D0-wt)*trcbl(i,j,k,ntrc)&
& +(.5D0+wt)*trcbl(i,j,kd,ntrc)))
end do
end do
end if
end do
!$omp end parallel