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