!$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 |