threadprivate Directive
10.1. threadprivate Directive#
The following examples demonstrate how to use the threadprivate directive to give each thread a separate counter.
//%compiler: clang
//%cflags: -fopenmp
/*
* name: threadprivate.1
* type: C
*/
int counter = 0;
#pragma omp threadprivate(counter)
int increment_counter()
{
counter++;
return(counter);
}
!!%compiler: gfortran
!!%cflags: -fopenmp
! name: threadprivate.1
! type: F-fixed
INTEGER FUNCTION INCREMENT_COUNTER()
COMMON/INC_COMMON/COUNTER
!$OMP THREADPRIVATE(/INC_COMMON/)
COUNTER = COUNTER +1
INCREMENT_COUNTER = COUNTER
RETURN
END FUNCTION INCREMENT_COUNTER
The following example uses threadprivate on a static variable:
//%compiler: clang
//%cflags: -fopenmp
/*
* name: threadprivate.2
* type: C
*/
int increment_counter_2()
{
static int counter = 0;
#pragma omp threadprivate(counter)
counter++;
return(counter);
}
The following example demonstrates unspecified behavior for the initialization of a threadprivate variable. A threadprivate variable is initialized once at an unspecified point before its first reference. Because a is constructed using the value of x (which is modified by the statement x++), the value of a.val at the start of the parallel region could be either 1 or 2. This problem is avoided for b, which uses an auxiliary const variable and a copy-constructor.
//%compiler: clang
//%cflags: -fopenmp
/*
* name: threadprivate.3
* type: C++
*/
class T {
public:
int val;
T (int);
T (const T&);
};
T :: T (int v){
val = v;
}
T :: T (const T& t) {
val = t.val;
}
void g(T a, T b){
a.val += b.val;
}
int x = 1;
T a(x);
const T b_aux(x); /* Capture value of x = 1 */
T b(b_aux);
#pragma omp threadprivate(a, b)
void f(int n) {
x++;
#pragma omp parallel for
/* In each thread:
* a is constructed from x (with value 1 or 2?)
* b is copy-constructed from b_aux
*/
for (int i=0; i<n; i++) {
g(a, b); /* Value of a is unspecified. */
}
}
The following examples show non-conforming uses and correct uses of the threadprivate directive.
The following example is non-conforming because the common block is not declared local to the subroutine that refers to it:
!!%compiler: gfortran
!!%cflags: -fopenmp
! name: threadprivate.2
! type: F-fixed
MODULE INC_MODULE
COMMON /T/ A
END MODULE INC_MODULE
SUBROUTINE INC_MODULE_WRONG()
USE INC_MODULE
!$OMP THREADPRIVATE(/T/)
!non-conforming because /T/ not declared in INC_MODULE_WRONG
END SUBROUTINE INC_MODULE_WRONG
The following example is also non-conforming because the common block is not declared local to the subroutine that refers to it:
!!%compiler: gfortran
!!%cflags: -fopenmp
! name: threadprivate.3
! type: F-fixed
SUBROUTINE INC_WRONG()
COMMON /T/ A
!$OMP THREADPRIVATE(/T/)
CONTAINS
SUBROUTINE INC_WRONG_SUB()
!$OMP PARALLEL COPYIN(/T/)
!non-conforming because /T/ not declared in INC_WRONG_SUB
!$OMP END PARALLEL
END SUBROUTINE INC_WRONG_SUB
END SUBROUTINE INC_WRONG
The following example is a correct rewrite of the previous example:
!!%compiler: gfortran
!!%cflags: -fopenmp
! name: threadprivate.4
! type: F-fixed
SUBROUTINE INC_GOOD()
COMMON /T/ A
!$OMP THREADPRIVATE(/T/)
CONTAINS
SUBROUTINE INC_GOOD_SUB()
COMMON /T/ A
!$OMP THREADPRIVATE(/T/)
!$OMP PARALLEL COPYIN(/T/)
!$OMP END PARALLEL
END SUBROUTINE INC_GOOD_SUB
END SUBROUTINE INC_GOOD
The following is an example of the use of threadprivate for local variables:
!!%compiler: gfortran
!!%cflags: -fopenmp
! name: threadprivate.5
! type: F-fixed
PROGRAM INC_GOOD2
INTEGER, ALLOCATABLE, SAVE :: A(:)
INTEGER, POINTER, SAVE :: PTR
INTEGER, SAVE :: I
INTEGER, TARGET :: TARG
LOGICAL :: FIRSTIN = .TRUE.
!$OMP THREADPRIVATE(A, I, PTR)
ALLOCATE (A(3))
A = (/1,2,3/)
PTR => TARG
I = 5
!$OMP PARALLEL COPYIN(I, PTR)
!$OMP CRITICAL
IF (FIRSTIN) THEN
TARG = 4 ! Update target of ptr
I = I + 10
IF (ALLOCATED(A)) A = A + 10
FIRSTIN = .FALSE.
END IF
IF (ALLOCATED(A)) THEN
PRINT *, 'a = ', A
ELSE
PRINT *, 'A is not allocated'
END IF
PRINT *, 'ptr = ', PTR
PRINT *, 'i = ', I
PRINT *
!$OMP END CRITICAL
!$OMP END PARALLEL
END PROGRAM INC_GOOD2
The above program, if executed by two threads, will print one of the following two sets of output:
a = 11 12 13
ptr = 4 i = 15
A is not allocated
ptr = 4
i = 5
or
A is not allocated
ptr = 4
i = 15
a = 1 2 3
ptr = 4
i = 5
The following is an example of the use of threadprivate for module variables:
!!%compiler: gfortran
!!%cflags: -fopenmp
! name: threadprivate.6
! type: F-fixed
MODULE INC_MODULE_GOOD3
REAL, POINTER :: WORK(:)
SAVE WORK
!$OMP THREADPRIVATE(WORK)
END MODULE INC_MODULE_GOOD3
SUBROUTINE SUB1(N)
USE INC_MODULE_GOOD3
!$OMP PARALLEL PRIVATE(THE_SUM)
ALLOCATE(WORK(N))
CALL SUB2(THE_SUM)
WRITE(*,*)THE_SUM
!$OMP END PARALLEL
END SUBROUTINE SUB1
SUBROUTINE SUB2(THE_SUM)
USE INC_MODULE_GOOD3
WORK(:) = 10
THE_SUM=SUM(WORK)
END SUBROUTINE SUB2
PROGRAM INC_GOOD3
N = 10
CALL SUB1(N)
END PROGRAM INC_GOOD3
The following example illustrates initialization of threadprivate variables for class-type T. t1 is default constructed, t2 is constructed taking a constructor accepting one argument of integer type, t3 is copy constructed with argument f():
//%compiler: clang
//%cflags: -fopenmp
/*
* name: threadprivate.4
* type: C++
*/
struct T { T (); T (int); ~T (); int t; };
int f();
static T t1;
#pragma omp threadprivate(t1)
static T t2( 23 );
#pragma omp threadprivate(t2)
static T t3 = f();
#pragma omp threadprivate(t3)
The following example illustrates the use of threadprivate for static class members. The threadprivate directive for a static class member must be placed inside the class definition.
//%compiler: clang
//%cflags: -fopenmp
/*
* name: threadprivate.5
* type: C++
*/
class T {
public:
static int i;
#pragma omp threadprivate(i)
};