Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using the fortran save attribute in parallel regions

I have a parallel region in my fortran code that uses OpenMP and calls subroutines that use variables with the save attribute in their scope. This is causing a problem because they are shared between threads, so my question is if there is a way to make these variables private while still being saved between subroutine calls, or will I need to input and output them?

Thanks

like image 503
Imaginary Avatar asked Nov 04 '25 07:11

Imaginary


1 Answers

You can do it using threadprivate - the code below shows a couple of slightly different approaches. But please note

a) The values are only guaranteed to be preserved between parallel regions if the parallel regions use the same number of threads

b) Please think carefully whether you really need save, save and parallel programming are very rarely good bed fellows. There are one or two good uses (see e.g. Fortran OpenMP with subroutines and functions), but if there is an alternative way to do what you want to do (e.g. passing through the argument list) this will almost certainly cause you less pain in the long run

(For some reason using a proper list breaks the formatting of the code below - if someone knows how to fix that, thanks!)

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$ 
like image 127
Ian Bush Avatar answered Nov 06 '25 04:11

Ian Bush



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!