The THREADPRIVATE directive allows you to specify named common blocks and named variables as private to a thread but global within that thread. Once you declare a common block or variable THREADPRIVATE, each thread in the team maintains a separate copy of that common block or variable. Data written to a THREADPRIVATE common block or variable remains private to that thread and is not visible to other threads in the team.
In the serial and MASTER sections of a program, only the master thread's copy of the named common block and variable is accessible.
Use the COPYIN clause on the PARALLEL, PARALLEL DO, PARALLEL SECTIONS or PARALLEL WORKSHARE directives to specify that upon entry into a parallel region, data in the master thread's copy of a named common block or named variable is copied to each thread's private copy of that common block or variable.
The THREADPRIVATE directive only takes effect if you specify the -qsmp compiler option.
where copyprivate_entity_list is:
>>-+-variable_name---------+----------------------------------->< '-/ common_block_name /-'
You cannot specify a THREADPRIVATE variable, common block, or the variables that comprise that common block in a PRIVATE, FIRSTPRIVATE, LASTPRIVATE, SHARED, or REDUCTION clause.
A THREADPRIVATE variable must have the SAVE attribute. For variables or common blocks declared in the scope of a module, the SAVE attribute is implied. If you declare the variable outside of the scope of the module, the SAVE attribute must be specified.
In THREADPRIVATE directives, you can only specify named variables and named common blocks.
A variable can only appear in a THREADPRIVATE directive in the scope in which it is declared, and a THREADPRIVATE variable or common block may only appear once in a given scope. The variable must not be an element of a common block, or be declared in an EQUIVALENCE statement.
You cannot specify the same common_block_name for both a THREADPRIVATE directive and a THREADLOCAL directive.
All rules and constraints that apply to named common blocks also apply to common blocks declared as THREADPRIVATE. See COMMON.
If you declare a common block as THREADPRIVATE in one scoping unit, you must declare it as THREADPRIVATE in all other scoping units in which it is declared.
On entry into any parallel region, a THREADPRIVATE variable, or a variable in a THREADPRIVATE common block is subject to the following criteria when declared in a COPYIN clause:
On entry into the first parallel region of the program, THREADPRIVATE variables or variables within a THREADPRIVATE common block not specified in a COPYIN clause are subject to the following criteria:
On entry into subsequent parallel regions of the program, THREADPRIVATE variables, or variables within a THREADPRIVATE common block not specified in a COPYIN clause, are subject to the following criteria:
You cannot access the name of a common block by use association or host association. Thus, a named common block can only appear on a THREADPRIVATE directive if the common block is declared in the scoping unit that contains the THREADPRIVATE directive. However, you can access the variables in the common block by use association or host association. For more information, see Host Association and Use Association.
The -qinit=f90ptr compiler option does not affect pointers that you have declared in a THREADPRIVATE common block.
The DEFAULT clause does not affect variables in THREADPRIVATE common blocks.
Example 1: In this example, the PARALLEL DO directive invokes multiple threads that call SUB1. The common block BLK in SUB1 shares the data that is specific to the thread with subroutine SUB2, which is called by SUB1.
PROGRAM TT INTEGER :: I, B(50) !$OMP PARALLEL DO SCHEDULE(STATIC, 10) DO I=1, 50 CALL SUB1(I, B(I)) ! Multiple threads call SUB1. ENDDO END PROGRAM TT SUBROUTINE SUB1(J, X) INTEGER :: J, X, A(100) COMMON /BLK/ A !$OMP THREADPRIVATE(/BLK/) ! Array a is private to each thread. ! ... CALL SUB2(J) X = A(J) + A(J + 50) ! ... END SUBROUTINE SUB1 SUBROUTINE SUB2(K) INTEGER :: C(100) COMMON /BLK/ C !$OMP THREADPRIVATE(/BLK/) ! ... C = K ! ... ! Since each thread has its own copy of ! common block BLK, the assignment of ! array C has no effect on the copies of ! that block owned by other threads. END SUBROUTINE SUB2
Example 2: In this example, each thread has its own copy of the common block ARR in the parallel section. If one thread initializes the common block variable TEMP, the initial value is not visible to other threads.
PROGRAM ABC INTEGER :: I, TEMP(100), ARR1(50), ARR2(50) COMMON /ARR/ TEMP !$OMP THREADPRIVATE(/ARR/) INTERFACE SUBROUTINE SUBS(X) INTEGER :: X(:) END SUBROUTINE END INTERFACE ! ... !$OMP PARALLEL SECTIONS !$OMP SECTION ! The thread has its own copy of the ! ... ! common block ARR. TEMP(1:100:2) = -1 TEMP(2:100:2) = 2 CALL SUBS(ARR1) ! ... !$OMP SECTION ! The thread has its own copy of the ! ... ! common block ARR. TEMP(1:100:2) = 1 TEMP(2:100:2) = -2 CALL SUBS(ARR2) ! ... !$OMP END PARALLEL SECTIONS ! ... PRINT *, SUM(ARR1), SUM(ARR2) END PROGRAM ABC SUBROUTINE SUBS(X) INTEGER :: K, X(:), TEMP(100) COMMON /ARR/ TEMP !$OMP THREADPRIVATE(/ARR/) ! ... DO K = 1, UBOUND(X, 1) X(K) = TEMP(K) + TEMP(K + 1) ! The thread is accessing its ! own copy of ! the common block. ENDDO ! ... END SUBROUTINE SUBS
The expected output for this program is:
Example 3: In the following example, local variables outside of a common block are declared THREADPRIVATE.
MODULE MDL INTEGER :: A(2) INTEGER, POINTER :: P INTEGER, TARGET :: T !$OMP THREADPRIVATE(A, P) END MODULE MDL PROGRAM MVAR USE MDL INTEGER :: I INTEGER OMP_GET_THREAD_NUM CALL OMP_SET_NUM_THREADS(2) A = (/1, 2/) T = 4 P => T !$OMP PARALLEL PRIVATE(I) COPYIN(A, P) I = OMP_GET_THREAD_NUM() IF (I .EQ. 0) THEN A(1) = 100 T = 5 ELSE IF (I .EQ. 1) THEN A(2) = 200 END IF !$OMP END PARALLEL !$OMP PARALLEL PRIVATE(I) I = OMP_GET_THREAD_NUM() IF (I .EQ. 0) THEN PRINT *, 'A(2) = ', A(2) ELSE IF (I .EQ. 1) THEN PRINT *, 'A(1) = ', A(1) PRINT *, 'P => ', P END IF !$OMP END PARALLEL END PROGRAM MVAR
If dynamic threads mechanism is disabled, the expected output is:
A(2) = 2 A(1) = 1 P => 5 or A(1) = 1 P => 5 A(2) = 2