Вы можете сделать это, используя threadprivate
- код ниже демонстрирует несколько несколько разных подходов. Но обратите внимание
a) Значения гарантированно сохраняются между параллельными областями только в том случае, если параллельные области используют одинаковое количество потоков
b) Пожалуйста, тщательно продумайте, действительно ли вам нужна save
, сохранить и параллельное программирование очень редко хороших собратьев. Есть одно или два хороших применения (см., Например, Fortran OpenMP с подпрограммами и функциями ), но если есть альтернативный способ сделать то, что вы хотите сделать (например, пройти через список аргументов), это почти наверняка в долгосрочной перспективе вам будет меньше боли
(По какой-то причине использование правильного списка нарушает форматирование кода ниже - если кто-то знает, как это исправить, спасибо!)
ian@eris:~/work/stack$ cat threadprivate.f90
Program test
Implicit None
Call do_something
Call do_something
Call do_something
Write( *, * )
!$omp parallel
Call do_something_else
Call do_something_else
Call do_something_else
!$omp end parallel
Contains
Subroutine do_something
Use omp_lib
Implicit None
Integer, Save :: calls = 0
Integer, Save :: stuff
Logical, Save :: first = .True.
!$omp threadprivate( first, stuff )
calls = calls + 1
! Shouldn't scope threadprivate variables - they are already private
!$omp parallel default( none ) shared( calls )
If( first ) Then
first = .False.
stuff = omp_get_thread_num()
Else
stuff = stuff + 1
End If
Write( *, '( 3( a, 1x, i2, 1x ) )' ) 'do something call ', calls, &
'thread = ', omp_get_thread_num(), 'stuff = ', stuff
!$omp end parallel
End Subroutine do_something
Subroutine do_something_else
Use omp_lib
Implicit None
Integer, Save :: calls = 0
Integer, Save :: stuff
Logical, Save :: first = .True.
!$omp threadprivate( first, stuff, calls )
calls = calls + 1
If( first ) Then
first = .False.
stuff = omp_get_thread_num()
Else
stuff = stuff + 1
End If
Write( *, '( 3( a, 1x, i2, 1x ) )' ) 'do something else call ', calls, &
'thread = ', omp_get_thread_num(), 'stuff = ', stuff
End Subroutine do_something_else
End Program test
ian@eris:~/work/stack$ gfortran -std=f2008 -Wall -Wextra -O -g -fcheck=all -pedantic -fopenmp threadprivate.f90
ian@eris:~/work/stack$ export OMP_NUM_THREADS=2
ian@eris:~/work/stack$ ./a.out
do something call 1 thread = 0 stuff = 0
do something call 1 thread = 1 stuff = 1
do something call 2 thread = 1 stuff = 2
do something call 2 thread = 0 stuff = 1
do something call 3 thread = 1 stuff = 3
do something call 3 thread = 0 stuff = 2
do something else call 1 thread = 1 stuff = 1
do something else call 2 thread = 1 stuff = 2
do something else call 3 thread = 1 stuff = 3
do something else call 1 thread = 0 stuff = 0
do something else call 2 thread = 0 stuff = 1
do something else call 3 thread = 0 stuff = 2
ian@eris:~/work/stack$ export OMP_NUM_THREADS=4
ian@eris:~/work/stack$ ./a.out
do something call 1 thread = 3 stuff = 3
do something call 1 thread = 2 stuff = 2
do something call 1 thread = 1 stuff = 1
do something call 1 thread = 0 stuff = 0
do something call 2 thread = 1 stuff = 2
do something call 2 thread = 3 stuff = 4
do something call 2 thread = 0 stuff = 1
do something call 2 thread = 2 stuff = 3
do something call 3 thread = 3 stuff = 5
do something call 3 thread = 1 stuff = 3
do something call 3 thread = 0 stuff = 2
do something call 3 thread = 2 stuff = 4
do something else call 1 thread = 3 stuff = 3
do something else call 2 thread = 3 stuff = 4
do something else call 3 thread = 3 stuff = 5
do something else call 1 thread = 1 stuff = 1
do something else call 2 thread = 1 stuff = 2
do something else call 3 thread = 1 stuff = 3
do something else call 1 thread = 0 stuff = 0
do something else call 2 thread = 0 stuff = 1
do something else call 3 thread = 0 stuff = 2
do something else call 1 thread = 2 stuff = 2
do something else call 2 thread = 2 stuff = 3
do something else call 3 thread = 2 stuff = 4
ian@eris:~/work/stack$