The THREADPRIVATE directive is used to make global file scope variables (C/C++) or common blocks (Fortran) local and persistent to a thread through the execution of multiple parallel regions.
The PRIVATE clause declares variables in its list to be private to each thread.
When developing with openMP, please make sure to keep the declaration of threadprivate/private variables be consistent during the execution. You should not using inconsistent declaration in different subroutines inside a same parallel block.
An example different combinations are attached for demonstration.
In the attached example, the declaration is correct for:
common block /MSP/;
variable SP0 in common block /SP/;
variable SP2 in common block /SP2/.
While the declaration is incorrect for:
common block /MP/;
variable SP1 in common block /SP/.
As we can see in the out.txt, we can always get consistent results for MSP1, SP0 and SP2 in main routine and subroutine for every threads.
But for SP1 and SP2, it is different in main routine and subroutine.
Useful links:
https://hpc-tutorials.llnl.gov/openmp/threadprivate_directive/
https://hpc-tutorials.llnl.gov/openmp/private_clause/
ifort -c main_threadprivate.f90 /Qauto /Qopenmp
ifort -c sub_thread.f90 /Qauto /Qopenmp
ifort -o threadprivate_test.exe main_threadprivate.obj sub_thread.obj
threadprivate_test.exe >out.txt
==================main_threadprivate.f90 ==========================
PROGRAM MAIN
! A DEMONSTRATION PROGRAM TO SHOW CORRECT AND INCORRECT WAY TO DECLARE
! THREADPRIVATE AND PRIVATE VARIABLES BY openMP.
!
IMPLICIT NONE
INTEGER MSP1,MP1,SP0,SP1,SP2,TTID,OMP_GET_THREAD_NUM,OMP_SET_NUM_THREADS
! MSP: MAIN+SUBROUTINE PRIVATE
COMMON /MSP/MSP1
COMMON /MP/MP1
COMMON /SP/SP0,SP1
COMMON /SP2/SP2
!$OMP THREADPRIVATE(/MSP/,/MP/)
!
!INITIALIZATION
MSP1 = 10
MP1 = 20
SP0 = 30
SP1 = 31
SP2 = 32
!
TTID = OMP_GET_THREAD_NUM()
!$OMP CRITICAL
WRITE(*,*) 'INITIAL VALUE IN MAIN MSP1=',MSP1, 'TTID=',TTID
WRITE(*,*) 'INITIAL VALUE IN MAIN MP1=', MP1, 'TTID=',TTID
WRITE(*,*) 'INITIAL VALUE IN MAIN, SP0=', SP0, 'TTID=',TTID
WRITE(*,*) 'INITIAL VALUE IN MAIN, SP1=', SP1, 'TTID=',TTID
WRITE(*,*) 'INITIAL VALUE IN MAIN, SP2=', SP2, 'TTID=',TTID
!$OMP END CRITICAL
!
WRITE(*,*) 'PARALLEL BEGINS'
!$OMP PARALLEL COPYIN(/MSP/) PRIVATE(SP1) FIRSTPRIVATE(SP2)
!
!$OMP CRITICAL
TTID = OMP_GET_THREAD_NUM()
MSP1=MSP1+TTID
MP1=MP1+TTID
SP0=SP0+TTID
SP1=SP1+TTID
SP2=SP2+TTID
WRITE(*,*) 'MAIN AFTER PARALLEL, MSP1=',MSP1,'TTID=',TTID
WRITE(*,*) 'MAIN AFTER PARALLEL, MP1=',MP1, 'TTID=',TTID
WRITE(*,*) 'MAIN AFTER PARALLEL, SP0=',SP0, 'TTID=',TTID
WRITE(*,*) 'MAIN AFTER PARALLEL, SP1=',SP1, 'TTID=',TTID
WRITE(*,*) 'MAIN AFTER PARALLEL, SP2=',SP2, 'TTID=',TTID
CALL SUB_THREAD(SP2)
!$OMP END CRITICAL
!
!$OMP END PARALLEL
STOP
END
==============sub_thread.f90================================
SUBROUTINE SUB_THREAD(SP2)
!
IMPLICIT NONE
INTEGER MSP1,MP1,SP0,SP1,SP2,TTID,OMP_GET_THREAD_NUM
!MSP MAIN+SUBROUTINE PRIVATE
COMMON /MSP/MSP1
COMMON /MP/MP1
COMMON /SP/SP0,SP1
!$OMP THREADPRIVATE(/MSP/)
!
TTID = OMP_GET_THREAD_NUM()
WRITE(*,*) 'SUB_THREAD, MSP1=',MSP1,'TTID=',TTID
WRITE(*,*) 'SUB_THREAD, MP1=',MP1, 'TTID=',TTID
WRITE(*,*) 'SUB_THREAD, SP0=',SP0, 'TTID=',TTID
WRITE(*,*) 'SUB_THREAD, SP1=',SP1, 'TTID=',TTID
WRITE(*,*) 'SUB_THREAD, SP2=',SP2, 'TTID=',TTID
WRITE(*,*) ' '
RETURN
END
=====================out.txt===================================
INITIAL VALUE IN MAIN MSP1= 10 TTID= 0
INITIAL VALUE IN MAIN MP1= 20 TTID= 0
INITIAL VALUE IN MAIN, SP0= 30 TTID= 0
INITIAL VALUE IN MAIN, SP1= 31 TTID= 0
INITIAL VALUE IN MAIN, SP2= 32 TTID= 0
PARALLEL BEGINS
MAIN AFTER PARALLEL, MSP1= 10 TTID= 0
MAIN AFTER PARALLEL, MP1= 20 TTID= 0
MAIN AFTER PARALLEL, SP0= 30 TTID= 0
MAIN AFTER PARALLEL, SP1= 0 TTID= 0
MAIN AFTER PARALLEL, SP2= 32 TTID= 0
SUB_THREAD, MSP1= 10 TTID= 0
SUB_THREAD, MP1= 20 TTID= 0
SUB_THREAD, SP0= 30 TTID= 0
SUB_THREAD, SP1= 31 TTID= 0
SUB_THREAD, SP2= 32 TTID= 0
MAIN AFTER PARALLEL, MSP1= 16 TTID= 6
MAIN AFTER PARALLEL, MP1= 6 TTID= 6
MAIN AFTER PARALLEL, SP0= 36 TTID= 6
MAIN AFTER PARALLEL, SP1= 6 TTID= 6
MAIN AFTER PARALLEL, SP2= 38 TTID= 6
SUB_THREAD, MSP1= 16 TTID= 6
SUB_THREAD, MP1= 20 TTID= 6
SUB_THREAD, SP0= 36 TTID= 6
SUB_THREAD, SP1= 31 TTID= 6
SUB_THREAD, SP2= 38 TTID= 6
MAIN AFTER PARALLEL, MSP1= 12 TTID= 2
MAIN AFTER PARALLEL, MP1= 2 TTID= 2
MAIN AFTER PARALLEL, SP0= 38 TTID= 2
MAIN AFTER PARALLEL, SP1= 2 TTID= 2
MAIN AFTER PARALLEL, SP2= 34 TTID= 2
SUB_THREAD, MSP1= 12 TTID= 2
SUB_THREAD, MP1= 20 TTID= 2
SUB_THREAD, SP0= 38 TTID= 2
SUB_THREAD, SP1= 31 TTID= 2
SUB_THREAD, SP2= 34 TTID= 2
MAIN AFTER PARALLEL, MSP1= 17 TTID= 7
MAIN AFTER PARALLEL, MP1= 7 TTID= 7
MAIN AFTER PARALLEL, SP0= 45 TTID= 7
MAIN AFTER PARALLEL, SP1= 7 TTID= 7
MAIN AFTER PARALLEL, SP2= 39 TTID= 7
SUB_THREAD, MSP1= 17 TTID= 7
SUB_THREAD, MP1= 20 TTID= 7
SUB_THREAD, SP0= 45 TTID= 7
SUB_THREAD, SP1= 31 TTID= 7
SUB_THREAD, SP2= 39 TTID= 7
MAIN AFTER PARALLEL, MSP1= 14 TTID= 4
MAIN AFTER PARALLEL, MP1= 4 TTID= 4
MAIN AFTER PARALLEL, SP0= 49 TTID= 4
MAIN AFTER PARALLEL, SP1= 4 TTID= 4
MAIN AFTER PARALLEL, SP2= 36 TTID= 4
SUB_THREAD, MSP1= 14 TTID= 4
SUB_THREAD, MP1= 20 TTID= 4
SUB_THREAD, SP0= 49 TTID= 4
SUB_THREAD, SP1= 31 TTID= 4
SUB_THREAD, SP2= 36 TTID= 4
MAIN AFTER PARALLEL, MSP1= 13 TTID= 3
MAIN AFTER PARALLEL, MP1= 3 TTID= 3
MAIN AFTER PARALLEL, SP0= 52 TTID= 3
MAIN AFTER PARALLEL, SP1= 3 TTID= 3
MAIN AFTER PARALLEL, SP2= 35 TTID= 3
SUB_THREAD, MSP1= 13 TTID= 3
SUB_THREAD, MP1= 20 TTID= 3
SUB_THREAD, SP0= 52 TTID= 3
SUB_THREAD, SP1= 31 TTID= 3
SUB_THREAD, SP2= 35 TTID= 3
MAIN AFTER PARALLEL, MSP1= 11 TTID= 1
MAIN AFTER PARALLEL, MP1= 1 TTID= 1
MAIN AFTER PARALLEL, SP0= 53 TTID= 1
MAIN AFTER PARALLEL, SP1= 1 TTID= 1
MAIN AFTER PARALLEL, SP2= 33 TTID= 1
SUB_THREAD, MSP1= 11 TTID= 1
SUB_THREAD, MP1= 20 TTID= 1
SUB_THREAD, SP0= 53 TTID= 1
SUB_THREAD, SP1= 31 TTID= 1
SUB_THREAD, SP2= 33 TTID= 1
MAIN AFTER PARALLEL, MSP1= 15 TTID= 5
MAIN AFTER PARALLEL, MP1= 5 TTID= 5
MAIN AFTER PARALLEL, SP0= 58 TTID= 5
MAIN AFTER PARALLEL, SP1= 5 TTID= 5
MAIN AFTER PARALLEL, SP2= 37 TTID= 5
SUB_THREAD, MSP1= 15 TTID= 5
SUB_THREAD, MP1= 20 TTID= 5
SUB_THREAD, SP0= 58 TTID= 5
SUB_THREAD, SP1= 31 TTID= 5
SUB_THREAD, SP2= 37 TTID= 5
======================END=============================