2016-02-11 2 views
4

Отказ от ответственности: Я совершенно уверен, что на это был дан ответ, но я и другой человек искали довольно тяжело, но безрезультатно.Fortran OpenMP с подпрограммами и функциями

У меня есть код, который выглядит примерно так:

 PROGRAM main 
!$omp parallel do 
!$omp private(somestuff) shared(otherstuff) 
     DO i=1,n 
     ... 
     CALL mysubroutine(args) 
     ... 
     a=myfunction(moreargs) 
     ... 
     ENDDO 
!$omp end parallel do 
     END PROGRAM 
     SUBROUTINE mysubroutine(things) 
     ... 
     END SUBROUTINE 
     FUNCTION myfunction(morethings) 
     ... 
     END FUNCTION 

Я не могу определить, где/как обрабатывать частное, общее, сокращение и т.д. положения для переменных в подпрограмме и функции. Я подозреваю, что в ответе могут быть некоторые нюансы, так как есть много разных способов, которые могли быть объявлены и распространены среди них. Итак, допустим, все переменные, с которыми связана основная программа, были определены в ней или в общих модулях, и что любые операции OMP для этих переменных могут обрабатываться в основном коде. Подпрограммы и функции используют некоторые из этих переменных и имеют некоторые из своих переменных. Итак, Я думаю, вопрос сводится к тому, как обрабатывать предложения для своих локальных переменных.

+0

Показать пример такой функции. Если локальные переменные не 'save', они не являются проблемой. –

+0

См. Http://stackoverflow.com/questions/22381795/is-there-an-easy-way-to-prepare-fortran-code-for-parallel-invocation. Эти ключевые слова, которые вы хотите исследовать, - это * thread-safety * и * поточно-безопасные * процедуры. –

+0

@ VladimirF, чтобы уточнить, у меня есть код для двух других, так что это скорее вопрос синтаксиса, чем безопасность потоков. «SAVE» находится в миксе, и подпрограмма и функция получают LOT, поэтому важно избегать ненужных повторных выделения памяти. Хотя, если использование 'SAVE' подвешивает их к куче, (и ущемляет производительность), тогда это не стоит. Тестирование может быть в порядке. – TTT

ответ

9

ОК, речь идет о различии между лексической и динамической степенью директив OpenMP и взаимодействием с переменным охватом. Лексическая степень директивы - это текст между началом и концом структурированного блока, следующий за директивой. Динамическая степень - это лексическая степень плюс операторы, выполняемые как часть любой подпрограммы, выполняемой в результате выражений в лексической степени. Так что в чем-то вроде

Program stuff 
    Implicit None 
    Real, Dimension(1:100) :: a 
    Call Random_number(a) 
    !$omp parallel default(none) shared(a) 
    Call sub(a) 
    !$omp end parallel 
Contains 
    Subroutine sub(a) 
     Real, Dimension(:), Intent(InOut) :: a 
     Integer :: i 
     !$omp do 
     Do i = 1, Size(a) 
     a(i) = 2.0 * a(i) 
     End Do 
    End Subroutine Sub 
End Program stuff 

(полностью тестировался, написанный прямо в здесь) лексической степени параллельной области, инициированной! $ OMP параллельно просто

Call sub(a) 

в то время как динамическая степень является вызовом и содержание подпрограммы. И для полноты терминологии! $ Omp do является примером осиротевшей директивы, директивы, которая не находится в лексической степени другой директивы, но в динамической степени. См

https://computing.llnl.gov/tutorials/openMP/#Scoping

для другого примера.

Почему это имеет значение? Ну, вы можете явно указывать переменные для сущностей в лексической области, а только массив a в этом случае, но для объектов, которые становятся определяемыми из-за выполняемой динамической степени, вы не можете этого сделать! Вместо OpenMP имеет ряд правил, которые в простых условиях являются

  1. Области аргументов подпрограммы унаследованный от точки вызова, то есть, если вы контекстные их как частные в начале лексической степени они остаются частными, и если они разделены, они остаются общедоступными.
  2. Локальные переменные для подпрограмм по умолчанию являются частными (поэтому я в приведенном выше примере является закрытым, как вы хотите), если они не объявлены с помощью атрибута SAVE (явно или неявно), и в этом случае они являются общими.

И в моем опыте, который доставит вам большую часть пути! Использование динамической степени в сочетании с сиротскими директивами - отличный способ держать под контролем программу OpenMP, и я должен сказать, что я не согласен с вышеуказанным комментарием, я считаю, что сиротские директивы по работе очень полезны!Таким образом, вы можете объединить все вышеперечисленное делать такие вещи, как

Program dot_test 
    Implicit None 
    Real, Dimension(1:100) :: a, b 
    Real :: r 
    a = 1.0 
    b = 2.0 
    !$omp parallel default(none) shared(a, b, r) 
    Call dot(a, b, r) 
    Write(*, *) r 
    !$omp end parallel 
Contains 
    Subroutine dot(a, b, r) 
    Real, Dimension(:), Intent(In ) :: a, b 
    Real,     Intent( Out) :: r 
    Real, Save :: s 
    Integer :: i 
    !$omp single 
    s = 0.0 
    !$omp end single 
    !$omp do reduction(+:s) 
    Do i = 1, Size(a) 
     s = s + a(i) * b(i) 
    End Do 
    !$omp end do 
    !$omp single 
    r = s 
    !$omp end single 
    End Subroutine dot 
End Program dot_test 
Wot now? gfortran -std=f95 -fopenmp -O -Wall -Wextra dot.f90 
Wot now? export OMP_NUM_THREADS=3 
Wot now? ./a.out 
    200.000000  
    200.000000  
    200.000000 

Эта простая ситуация несколько усложняется модулей переменных и общих блоков, так что не использовать глобальные переменные ... но если вы они должны по своей default shared, если не объявлено как threadprivate. См

https://computing.llnl.gov/tutorials/openMP/#THREADPRIVATE

для примера.

+0

Приятный пример, я был неправ. Также полезно использовать переменную 'save', которую вы показываете. Существует хорошее обсуждение сиротских директив в параллельном программировании Chandra в OpenMP. –

Смежные вопросы