Россия, г. Санкт-Петербург |
Основные конструкции OpenMP
Директива if
Директива (предложение) OpenMP if используется для организации условного выполнения потоков в параллельном структурном блоке.
Предложение OpenMP
if( expression )
определяет условие выполнения параллельных потоков в последующем параллельном структурном блоке. Если выражение expression принимает значение TRUE (Истина), то потоки в последующем параллельном структурном блоке выполняются. В противном случае, когда выражение expression принимает значение FALSE (Ложь), потоки в последующем параллельном структурном блоке не выполняются.
В качестве иллюстрации рассмотрим фрагмент программы (Пример 2.12).
c$omp parallel do if (n .ge. 2000) do i = 1, n a (i) = b (i)*c + d (i) enddo2.12. Пример использования директивы OpenMP if в параллельной области программы
В этом примере цикл распараллеливается только в том случае ( n>2000 ), когда параллельная версия будет заведомо быстрее последовательной. Напомним, что трудоемкость образования параллельных потоков эквивалентна примерно трудоемкости 1000 операций.
Директива reduction
Директива OpenMP reduction позволяет собрать вместе в главном потоке результаты вычислений частичных сумм, разностей и т. п. из параллельных потоков последующего параллельного структурного блока.
В предложении OpenMP
reduction( operator | intrinsic: var1 [, var2,..., varN])
определяется operator - операции ( +, -, *, / и т. п.) или функции, для которых будут вычисляться соответствующие частичные значения в параллельных потоках последующего параллельного структурного блока. Кроме того, определяется список локальных переменных var1, var2, ..., varN, в котором будут сохраняться соответствующие частичные значения. После завершения всех параллельных процессов частичные значения складываются (вычитаются, перемножаются и т. п.), и результат сохраняется в одноименной общей переменной.
В качестве иллюстрации рассмотрим фрагмент программы (пример 2.13).
c$omp do shared (x) private (i) c$omp& reduction (+ : sum) do i = 1, N sum = sum + x (I) enddo2.13. Пример вычисления суммы с использованием директивы OpenMP reduction в параллельной области программы
В этом примере в каждом параллельном потоке определена локальная переменная sum для вычисления частичных сумм. После завершения параллельных потоков все локальные переменные sum суммируются, а результат сохраняется в одноименной общей (глобальной) переменной sum.
Во фрагменте программы (пример 2.14) вычисляется минимальное значение по результатам вычисления частичных минимумов, вычисленных в параллельных потоках. В этом примере в каждом параллельном потоке определяются локальные минимумы по результатам сравнения значений x(i) и gmin. После завершения всех параллельных потоков вычисляется значение общей переменной gmin по результатам сравнения значений локальных переменных gmin в параллельных потоках.
c$omp do shared (x) private (i) c$omp& reduction (min : gmin) do i = 1, N gmin = min (gmin, x (i)) enddo2.14. Пример вычисления минимума с использованием директивы OpenMP reduction в параллельной области программы
В языке Fortran в качестве параметров operator и intrinsic в предложениях reduction допускаются следующие операции и функции:
- параметр operator может быть одной из следующих арифметических или логических операций: +, -, *, .and. , .or. , .eqv. , .neqv.;
- параметр intrinsic может быть одной из следующих функций: max, min, iand, ior, ieor.
В языке C/C++ в качестве параметров operator и intrinsic в предложениях reduction допускаются следующие операции и функции:
- параметр operator может быть одной из следующих арифметических или логических операций: +, -, *, &, ^, &&, || ;
- параметр intrinsic может быть одной из следующих функций: max, min ;
- указатели и ссылки в предложениях reduction использовать строго запрещено!
Директива copyin
Директива OpenMP copyin используется для передачи данных из главного потока в параллельные потоки, называемой миграцией данных. Механизмы реализации этой директивы в языках C/C++ и Fortran различны. Рассмотрим далее реализации этой директивы поочередно в C/C++ и Fortran.
Предложение OpenMP в языке C/C++
copyin( var1 [, var2[, ...[, varN]]] )
определяет список локальных переменных var1, var2, ..., varN, которым присваиваются значения из одноименных общих переменных, заданных в глобальном потоке.
В Fortran в качестве параметров директивы OpenMP copyin задаются имена common -блоков ( cb1, cb2, ..., cbN ), в которых описаны мигрирующие переменные
copyin( /cb1/ [, /cb2/ [, ...[, /cbN/ ]]] )
т.е. такие переменные из глобального потока, которые передают свои значения своим копиям, определенным в параллельных потоках в качестве локальных переменных.
В качестве иллюстрации миграции данных рассмотрим фрагмент Fortran-программы (Пример 2.15). В этом примере мигрирующая целочисленная переменная x хранится в common -блоке mine. Значение этой общей переменной задается в главном потоке. В каждом параллельном потоке используется своя локальная переменная х, которой присваивается значение общей переменной x.
integer : : x, tid integer, external :: omp_get_thread_num ( ) common/mine/ x ! $omp threadprivate (/mine/) x=33 call omp_set_num_threads (4) ! $omp parallel private (tid) copyin (/mine/) tid=omp_get_thread_num ( ) print *, 'T: ',tid, ' x = ', x ! $omp end parallel2.15. Пример использования директивы OpenMP copyin для организации миграции данных в Fortran-программе
Результаты работы программы:
T: 1 x = 33 T: 2 x = 33 T: 0 x = 33 T: 3 x = 33
Директива for
Директива OpenMP for используется для организации параллельного выполнения петель циклов в программах, написанных на языке C/C++.
Предложение OpenMP в программе на C/C++
#pragma omp for
означает, что оператор for, следующий за этим предложением, будет выполняться в параллельном режиме, т. е. каждой петле этого цикла будет соответствовать собственный параллельный поток.
В качестве иллюстрации использования директивы OpenMP for рассмотрим фрагмент программы на языке C (Пример 2.16). В этом примере петли цикла оператора for реализуются как набор параллельных потоков. По умолчанию в конце цикла реализуется функция синхронизации barrier (барьер). Для отмены функции barrier следует воспользоваться предложением OpenMP nowait.
#pragma omp parallel shared (a, b) private (j) { #pragma omp for for (j=0; j<N; j++) a [j] = a [j] + b [j];2.16. Пример использования директивы OpenMP for для организации параллельной обработки петель циклов в программе на языке C/C++
Директива do
Директива OpenMP do используется для организации параллельного выполнения петель циклов в программах, написанных на языке Fortran. Предложения OpenMP в программе на языке Fortran
c$omp [ parallel ] do [ предложение [ предложение [ … ]]] do loop [c$omp end do [nowait]]
означает, что петли ( loop ) оператора do будут реализованы как параллельные процессы. Последнее предложение, содержащее end do, завершает параллельный цикл do. Оно не является обязательным, но может включать предложение nowait для отмены функции синхронизации barrier, неявно присутствующей в конце цикла do. В качестве предложений в директиве do возможны следующие конструкции:
- private( list )
- firstprivate( list )
- lastprivate( list )
- reduction( operator : list ) o ordered
- schedule( kind [,chunk_size] )
- nowait
Большинство из этих OpenMP-конструкций уже было рассмотрено ранее. А некоторые, такие как ordered и schedule( kind [,chunk_size] ), будут рассмотрены далее.
Пример фрагмента программы на языке Fortran c применением директивы OpenMP do для распараллеливания выполнения петель цикла приведен в примере 2.17.
с$omp parallel do do i = 1, n a (i) = b (i) *c+ d (i) enddo2.17. Пример использования директивы OpenMP do для организации параллельной обработки петель циклов в программе на языке Fortran