!$OMP DirectiveName Optional_CLAUSES... ... ... Program statements between the !$OMP lines ... are executed in parallel by all threads ... !$OMP END DirectiveName |
export OMP_NUM_THREADS=... Example: export OMP_NUM_THREADS=8 |
|
PROGRAM Main !$OMP PARALLEL print *, "Hello World !" !$OMP END PARALLEL END |
|
|
Make sure you do it on compute.
You will see "Hello World !!!" printed EIGHT times !!!
(Remove the #pragma line and you get ONE line)....
|
Fortran uses option keywords to define private (non-shared) (and shared) variables....
|
PROGRAM Main IMPLICIT NONE integer :: N ! Shared N = 1001 print *, "Before parallel section: N = ", N !$OMP PARALLEL N = N + 1 print *, "Inside parallel section: N = ", N !$OMP END PARALLEL print *, "After parallel section: N = ", N END |
|
|
You should see the value for N at the end is not always 1009, it could be less. This is evidence of asynchronous update.
PROGRAM Main IMPLICIT NONE integer :: N ! Shared N = 1001 print *, "Before parallel section: N = ", N !$OMP PARALLEL PRIVATE(N) N = N + 1 print *, "Inside parallel section: N = ", N !$OMP END PARALLEL print *, "After parallel section: N = ", N END |
|
|
Before parallel section: N = 1001
Inside parallel section: N = 1
Inside parallel section: N = 1
Inside parallel section: N = 1
Inside parallel section: N = 1
Inside parallel section: N = 1
Inside parallel section: N = 1
Inside parallel section: N = 1
Inside parallel section: N = 1
After parallel section: N = 1001
|
Each thread has its own variable N
This variable N is different from the "program" variable defined in the main program !!!
| Function Name | Effect |
|---|---|
| omp_set_num_threads(int nthread) | Set size of thread team |
| INTEGER omp_get_num_threads() | return size of thread team |
| INTEGER omp_get_max_threads() | return max size of thread team (typically equal to the number of processors |
| INTEGER omp_get_thread_num() | return thread ID of the thread that calls this function |
| INTEGER omp_get_num_procs() | return number of processors |
| LOGICAL omp_in_parallel() | return TRUE if currently in a PARALLEL segment |
PROGRAM Main
IMPLICIT NONE
INTEGER :: nthreads, myid
INTEGER, EXTERNAL :: OMP_GET_THREAD_NUM, OMP_GET_NUM_THREADS
!$OMP PARALLEL private(nthreads, myid)
myid = OMP_GET_THREAD_NUM()
print *, "Hello I am thread ", myid
if (myid == 0) then
nthreads = OMP_GET_NUM_THREADS()
print *, "Number of threads = ", nthreads
end if
!$OMP END PARALLEL
END
|
|
|
Hello I am thread 7 Hello I am thread 5 Hello I am thread 1 Hello I am thread 0 Hello I am thread 2 Number of threads = 8 Hello I am thread 4 Hello I am thread 3 Hello I am thread 6 |
|
|
|
PROGRAM Min
IMPLICIT NONE
INTEGER, PARAMETER :: MAX = 10000000
DOUBLE PRECISION, DIMENSION(MAX) :: x
DOUBLE PRECISION, DIMENSION(10) :: my_min
DOUBLE PRECISION :: rmin
INTEGER :: num_threads
INTEGER :: i, n
INTEGER :: id, start, stop
! ===========================================================
! Declare the OpenMP functions
! ===========================================================
INTEGER, EXTERNAL :: OMP_GET_THREAD_NUM, OMP_GET_NUM_THREADS
! ===================================
! Parallel section: Find local minima
! ===================================
!$OMP PARALLEL PRIVATE(i, id, start, stop, num_threads, n)
num_threads = omp_get_num_threads()
n = MAX/num_threads
id = omp_get_thread_num()
! ----------------------------------
! Find my own starting index
! ----------------------------------
start = id * n + 1 !! Array start at 1
! ----------------------------------
! Find my own stopping index
! ----------------------------------
if ( id <> (num_threads-1) ) then
stop = start + n
else
stop = MAX
end if
! ----------------------------------
! Find my own min
! ----------------------------------
my_min(id+1) = x(start)
DO i = start+1, stop
IF ( x(i) < my_min(id+1) ) THEN
my_min(id+1) = x(i)
END IF
END DO
!$OMP END PARALLEL
! ===================================
! Find min over the local minima
! ===================================
rmin = my_min(1)
DO i = 2, num_threads
IF ( rmin < my_min(i) ) THEN
rmin = my_min(i)
END IF
END DO
print *, "min = ", rmin
END PROGRAM
|
|
|
!$OMP CRITICAL
... statements are guaranteed to be executed
,,, by ONE thread at any one time
!$OMP END CRITICAL
|
PROGRAM Compute_PI
IMPLICIT NONE
INTEGER, EXTERNAL :: OMP_GET_THREAD_NUM, OMP_GET_NUM_THREADS
INTEGER N, i
INTEGER id, num_threads
DOUBLE PRECISION w, x, sum
DOUBLE PRECISION pi, mypi
N = 50000000 !! Number of intervals
w = 1.0d0/N !! width of each interval
sum = 0.0d0
!$OMP PARALLEL PRIVATE(i, id, num_threads, x, mypi)
num_threads = omp_get_num_threads()
id = omp_get_thread_num()
mypi = 0.0d0;
DO i = id, N-1, num_threads
x = w * (i + 0.5d0)
mypi = mypi + w*f(x)
END DO
!$OMP CRITICAL
pi = pi + mypi
!$OMP END CRITICAL
!$OMP END PARALLEL
PRINT *, "Pi = ", pi
END PROGRAM
|
|
|
The division of labor (splitting the work of a for-loop) of a for-loop can be done in OpenMP through a special Parallel LOOP construct.
!$OMP DO
DO index = ....
.... ! Division of labor is taken care of
! by the Fortran compiler
END DO
!$OMP END DO
|
Each iteration of the for-loop is executed exactly once by each thread.
The loop variable used in the Parallel LOOP construct is by default PRIVATE (other variables are still by default SHARED)
PROGRAM Compute_PI
IMPLICIT NONE
INTEGER N, i, num_threads
DOUBLE PRECISION w, x, sum
DOUBLE PRECISION pi, mypi
N = 50000000 !! Number of intervals
w = 1.0d0/N !! width of each interval
sum = 0.0d0
!$OMP PARALLEL PRIVATE(x, mypi)
mypi = 0.0d0;
!$OMP DO
DO i = 0, N-1 !! Parallel Loop
x = w * (i + 0.5d0)
mypi = mypi + w*f(x)
END DO
!$OMP END DO
!$OMP CRITICAL
pi = pi + mypi
!$OMP END CRITICAL
!$OMP END PARALLEL
PRINT *, "Pi = ", pi
END PROGRAM
|
|
|
setenv STACKSIZE nBytes |