MRI.COM

OpenMP スレッド並列化

OpenMPによるスレッド並列化を行う場所を以下のように!$omp parallel と!$omp end parallel で挟む。

!$omp parallel

!$omp end parallel

この挟まれた区画の do loop に対して並列化を行う場合には、do loop の前に!$omp do をつける。 do loop の場合には、!$omp end do を省略できる。MRI.COMではこの省略形を基本とする。

!$omp parallel

!$omp do
do j = 1, jmut

end do 

!$omp end parallel

両者を一行にまとめることもできる。

!$omp parallel do
do j = 1, jmut

end do 
!$omp end parallel do

ただし、以下のように、並列化したloopが複数続いている場合には、!$omp parallel の指示行を何度も書くよりも、いちどだけ!$omp parallel を指定して中に!$omp do を複数書いた方が速い。(機種依存であろうが、fx100 で調査済み). ただし、スレッド間同期のタイミング等を意識して実装しないと、想定した動作をしない場合があるので注意が必要 (OpenMPスレッド並列の失敗例)

!$omp parallel

!$omp do
do j = 1, jmut

end do 

!$omp do
do j = 1, jmut

end do 

!$omp end parallel

!$omp parallel で挟まれた領域の一部の処理に対して、スレッド並列実行に制限をかけることもできる。 スレッド計算の同時実行数を1に制限したい場合は、!$omp critical !$omp end critical で挟む。 同時実行数は1に制限されるが、全てのスレッドで該当領域の処理が順番に行われることに注意。

io や call 文などのように単一スレッドで1度だけ計算をしたい場合には、!$omp single !$omp end single で挟む。 単一スレッドだけで処理が実行され、他のスレッドは何もしない。 処理が実行されるスレッド番号は決まっていない。!$omp end single の後に暗黙的にスレッド間同期がとられるが、!$omp single の前では同期はとられないことに注意。

!$omp parallel

!$omp do
do j = 1, jmut

end do 

!$omp single
   call hogehoge
!$omp end single
  

!$omp do
do j = 1, jmut

end do 

!$omp end parallel

スレッド番号0のスレッドでのみ実行したい場合は !$omp master !$omp end master で挟む。 single 指示文と異なり、入口だけでなく出口でもスレッド間同期がとられないことに注意したい。

do loopの中の変数はデフォルトではshared となっていて共用される。それぞれのスレッドが別の変数を持つ必要が場合には private としてする必要がある。ただし、do loop のループ制御変数はデフォルトでprivate となっている。(privateと明示しても良い)

!$omp parallel

!$omp do private(hl1)
do j = 1, jmut
  hl1 = a(j)
end do 

!$omp end parallel

ループが多重となり、ループの間に依存関係がない場合には、一般には一番外側にのみかける。 ただし、その場合には内側ループのループ制御変数はprivate 指定にする必要がある。

!$omp parallel

!$omp do private (hl1, i)
do j = 1, jmut
 do i = 1, imut 
     hl1 = a(i,j)
  end do 
end do 

!$omp end parallel