workshare Construct
3.13. workshare Construct#
The following are examples of the workshare construct.
In the following example, workshare spreads work across the threads executing the parallel region, and there is a barrier after the last statement. Implementations must enforce Fortran execution rules inside of the workshare block.
!!%compiler: gfortran
!!%cflags: -fopenmp
! name: workshare.1
! type: F-fixed
SUBROUTINE WSHARE1(AA, BB, CC, DD, EE, FF, N)
INTEGER N
REAL AA(N,N), BB(N,N), CC(N,N), DD(N,N), EE(N,N), FF(N,N)
!$OMP PARALLEL
!$OMP WORKSHARE
AA = BB
CC = DD
EE = FF
!$OMP END WORKSHARE
!$OMP END PARALLEL
END SUBROUTINE WSHARE1
In the following example, the barrier at the end of the first workshare region is eliminated with a nowait clause. Threads doing CC = DD immediately begin work on EE = FF when they are done with CC = DD.
!!%compiler: gfortran
!!%cflags: -fopenmp
! name: workshare.2
! type: F-fixed
SUBROUTINE WSHARE2(AA, BB, CC, DD, EE, FF, N)
INTEGER N
REAL AA(N,N), BB(N,N), CC(N,N)
REAL DD(N,N), EE(N,N), FF(N,N)
!$OMP PARALLEL
!$OMP WORKSHARE
AA = BB
CC = DD
!$OMP END WORKSHARE NOWAIT
!$OMP WORKSHARE
EE = FF
!$OMP END WORKSHARE
!$OMP END PARALLEL
END SUBROUTINE WSHARE2
The following example shows the use of an atomic directive inside a workshare construct. The computation of SUM(AA) is workshared, but the update to R is atomic.
!!%compiler: gfortran
!!%cflags: -fopenmp
! name: workshare.3
! type: F-fixed
SUBROUTINE WSHARE3(AA, BB, CC, DD, N)
INTEGER N
REAL AA(N,N), BB(N,N), CC(N,N), DD(N,N)
REAL R
R=0
!$OMP PARALLEL
!$OMP WORKSHARE
AA = BB
!$OMP ATOMIC UPDATE
R = R + SUM(AA)
CC = DD
!$OMP END WORKSHARE
!$OMP END PARALLEL
END SUBROUTINE WSHARE3
Fortran WHERE and FORALL statements are compound statements, made up of a control part and a statement part. When workshare is applied to one of these compound statements, both the control and the statement parts are workshared. The following example shows the use of a WHERE statement in a workshare construct.
Each task gets worked on in order by the threads:
AA = BB then
CC = DD then
EE .ne. 0 then
FF = 1 / EE then
GG = HH
!!%compiler: gfortran
!!%cflags: -fopenmp
! name: workshare.4
! type: F-fixed
SUBROUTINE WSHARE4(AA, BB, CC, DD, EE, FF, GG, HH, N)
INTEGER N
REAL AA(N,N), BB(N,N), CC(N,N)
REAL DD(N,N), EE(N,N), FF(N,N)
REAL GG(N,N), HH(N,N)
!$OMP PARALLEL
!$OMP WORKSHARE
AA = BB
CC = DD
WHERE (EE .ne. 0) FF = 1 / EE
GG = HH
!$OMP END WORKSHARE
!$OMP END PARALLEL
END SUBROUTINE WSHARE4
In the following example, an assignment to a shared scalar variable is performed by one thread in a workshare while all other threads in the team wait.
!!%compiler: gfortran
!!%cflags: -fopenmp
! name: workshare.5
! type: F-fixed
SUBROUTINE WSHARE5(AA, BB, CC, DD, N)
INTEGER N
REAL AA(N,N), BB(N,N), CC(N,N), DD(N,N)
INTEGER SHR
!$OMP PARALLEL SHARED(SHR)
!$OMP WORKSHARE
AA = BB
SHR = 1
CC = DD * SHR
!$OMP END WORKSHARE
!$OMP END PARALLEL
END SUBROUTINE WSHARE5
The following example contains an assignment to a private scalar variable, which is performed by one thread in a workshare while all other threads wait. It is non-conforming because the private scalar variable is undefined after the assignment statement.
!!%compiler: gfortran
!!%cflags: -fopenmp
! name: workshare.6
! type: F-fixed
SUBROUTINE WSHARE6_WRONG(AA, BB, CC, DD, N)
INTEGER N
REAL AA(N,N), BB(N,N), CC(N,N), DD(N,N)
INTEGER PRI
!$OMP PARALLEL PRIVATE(PRI)
!$OMP WORKSHARE
AA = BB
PRI = 1
CC = DD * PRI
!$OMP END WORKSHARE
!$OMP END PARALLEL
END SUBROUTINE WSHARE6_WRONG
Fortran execution rules must be enforced inside a workshare construct. In the following example, the same result is produced in the following program fragment regardless of whether the code is executed sequentially or inside an OpenMP program with multiple threads:
!!%compiler: gfortran
!!%cflags: -fopenmp
! name: workshare.7
! type: F-fixed
SUBROUTINE WSHARE7(AA, BB, CC, N)
INTEGER N
REAL AA(N), BB(N), CC(N)
!$OMP PARALLEL
!$OMP WORKSHARE
AA(1:50) = BB(11:60)
CC(11:20) = AA(1:10)
!$OMP END WORKSHARE
!$OMP END PARALLEL
END SUBROUTINE WSHARE7