Основными средствами программирования для многопроцессорных вычислительных систем являются три библиотеки, оформленные как стандарты: библиотека OpenMP для систем с общей памятью (мультипроцессоров) и библиотека MPI (Message Passing Interface) для систем с распределенной памятью (мультикомпьютеров). Для программирования гетерогенных вычислительных систем с распределенной памятью используется библиотека PVM. Все указанные библиотеки написаны на языках высокого уровня и являются в достаточной степени аппаратно-независимыми. В то же время наблюдается зависимость этих библиотек от операционной среды. В некоторых случаях библиотеки строятся не из процедур, а из классов С++.
Общие сведения об интерфейсе OpenMP.
Стандартом OpenMP занимается организация OpenMP ARB (ARchitecture Board). В 1997 года этой организацией был выпущен стандарт для языка OpenMP Fortran – расширения языка Фортран 77. Позже вышли аналогичные стандарты для языков Си и Фортран 90/95.
OpenMP расширяет последовательный язык программирования для мультипроцессорных систем набором директив компилятора и библиотечных функций. OpenMP-программа (программа, построенная с использованием средств библиотеки OpenMP) начинает свое выполнение как один процесс, называемый главной нитью. Главная нить выполняется последовательно, пока не встретится первая параллельная область программы.
OpenMP-программа должна без всяких изменений работать на однопроцессорной платформе в качестве последовательной программы. Директивы OpenMP в этом случае просто игнорируются компилятором, а вместо вызовов функций OpenMP вставляются "заглушки".
OpenMP можно рассматривать как высокоуровневую надстройку над легковесными процессами (threads) – параграф 1.2.
Основные директивы.
Директивы OpenMP с точки зрения языка Фортран являются комментариями и начинаются с комбинации символов !$OMP, *$OMP. Директивы можно разделить на 3 категории: определение параллельной области, определение параллельных конструкций, синхронизация.

Директивы определения параллельной области имеют вид
!$OMP PARALLEL [список спецификаций]
      блок
!$OMP END PARALLEL
В списке спецификаций могут описываться классы данных, используемых в параллельной области, условия выполнения области и пр. Допускаются следующие спецификации:
PRIVATE();
SHARED();
DEFAULT();
FIRSTPRIVATE();
REDUCTION();
IF();
COPYIN()
Условие выполнения имеет вид IF <скалярное логическое выражение>. Если условие выполнения задано, то вход в данную параллельную область осуществляется только при выполнении указанного условия. Эта возможность может быть полезна, например, для того, чтобы избежать распараллеливания при малом объеме вычислений в блоке.
Остальные из указанных спецификаций будут рассмотрены позже.
При входе в параллельную область порождается некоторое количество N новых нитей, т.е. образуется бригада из N нитей, а порождающая нить получает номер 0 и становится главной нитью бригады. При выходе из параллельной области главная нить дожидается завершения остальных нитей и продолжает выполнение. Число нитей определяется с помощью переменной окружения OMP_NUM_THREADS либо путем вызова функции OMP_SET_NUM_THREADS. Нити, соответствующие параллельной области, выполняются параллельно на разных процессорах мультипроцессора. Распределение нитей по процессорам мультипроцессора находится в ведении его операционной системы.
Параллельные области могут быть вложенными. Внутренней параллельной области при этом ставится в соответствие одна из нитей бригады нитей, которая выполняет внешнюю параллельную область.

К директивам определения параллельных конструкций относится директивы DO ... ENDDO, SECTIONS ... ENDSECTIONS, SINGLE ... ENDSINGLE. Параллельная конструкция определяет объем работ нитей в бригаде, но не создает новых нитей. Конструкция DO служит для распределения витков цикла между нитями, а конструкция SECTIONS – для распределения между нитями указанных секций программы.
Для параллельной области можно указать классы используемых в ней данных:

Директивы определения параллельного цикла имеют вид
!$OMP  DO[список спецификаций]
       цикл
[!$OMP ENDDO[NOWAIT]]
По умолчанию, в конце цикла происходит неявная синхронизация нитей – дальнейшее выполнение нитей происходит только после достижения всеми ими данной точки. Синхронизацию можно запретить с помощью спецификации NOWAIT.
В заголовке параллельного цикла допускаются следующие спецификации:
PRIVATE();
FIRSTPRIVATE();
LASTPRIVATE();
REDUCTION();
SCHEDULE();
ORDERED()
Спецификация SCHEDULE (способ[,m]) определяет способ распределения итераций по нитям. Допустимы следующие значения аргумента э той спецификации;:
Остальные спецификации будут рассмотрены позже.
Пример 1
Параллельная область содержит вложенный цикл. Внешний цикл будет выполняться параллельно, внутренний цикл – последовательно.
!$OMP PARALLEL
!$OMP DO
      DO I=1,N
         DO j=1,M
            тело цикла
         END DO
      END DO
!$OMP END DO
!$OMP END PARALLEL
Директивы определения параллельных секций имеют вид
!$OMP SECTIONS[список спецификаций]
   [!$OMP SECTION]
      блок операторов
   [!$OMP SECTION]
      блок операторов
...
!$OMP ENDSECTIONS[NOWAIT]
Допускаются следующие спецификации, которые будут рассмотрены позже:
PRIVATE();
FIRSTPRIVATE();
LASTPRIVATE();
REDUCTION()
Директивы SECTIONS, ENDSECTIONS являются не итерационными конструкциями и порождают количество нитей, равное количеству директив SECTIONS. По умолчанию, перед директивой ENDSECTIONS происходит неявная синхронизация нитей, которая может быть отменена спецификацией NOWAIT.
Пример 2
Параллельная секция содержит три блока операторов, которые могут выполняться параллельно.
!$OMP PARALLEL
   !$OMP SECTIONS
      !$OMP SECTION
         блок операторов 1
      !$OMP SECTION
         блок операторов 2
      !$OMP SECTION
         блок операторов 3
   !$OMP END SECTIONS
!$OMP END PARALLEL
В Open MP имеются также директивы определения параллельной секции, которая должна исполняться одной нитью:
!$OMP SINGLE[список спецификаций]
   блок операторов
!$OMP ENDSINGLE[NOWAIT]
Мы не будем останавливаться на данных директивах.
Классы данных.
Для управления данными во время выполнения параллельных конструкций используются следующие спецификации:
SHARED;
PRIVATE;
DEFAULT;
FIRSTPRIVATE;
LASTPRIVATE;
REDUCTION;
COPYIN
Рассмотрим основные из перечисленных спецификаций.
Спецификаций
SHARED(список переменных)
Здесь в списке переменных перечисляются переменные, которые являются общими для всех нитей соответствующей параллельной области или конструкции. По умолчанию, переменные COMMON-блоков, а также переменные, порожденные вне параллельной области или конструкции, при входе в эту область или конструкцию остаются общими.
Спецификаций
PRIVATE(список переменных)
В списке переменных перечисляются переменные, которые являются приватными для каждой из нитей, соответствующих параллельной области или конструкции. При входе в параллельную область или конструкцию для каждой из нитей создается отдельный экземпляр переменных (локальная копия переменных). Начальные значения этих данных по умолчанию не определены. Переменные, порожденные внутри параллельной области или конструкции, являются приватными.
Спецификация
DEFAULT(PRIVATE| SHARED| NONE)
Спецификация определяет вид переменных, которые ранее не определены в программе с помощью спецификаций SHARED, PRIVATE.
Спецификаций
FIRSTPRIVATE(список переменных)
В списке переменных перечисляются те приватные переменные, которые при входе в параллельную область или конструкцию должны инициализироваться значениям соответствующих исходных переменных.
Спецификаций
COPYIN(список переменных)
В списке переменных могут содержаться имена COMMON-блоков и/или имена отдельных переменных из этих блоков. При входе в параллельную область или конструкцию приватные копии этих данных инициализируются значениям соответствующих исходных переменных. Указанные COMMON-блоки должны быть предварительно определены в директиве
THREADPRIVATE(/имя COMMON-блока/[, имя COMMON-блока]...)
Средства синхронизации.
Выше уже упоминались неявные средства синхронизации OpenMP. Кроме того, имеются также директивы и подпрограммы для явной синхронизации.

!$OMP MASTER
   блок операторов
!$OMP END MASTER
определяют блок, который будет выполняться только главной нитью. Остальные нити начнут работу только после завершения работы этого блока.
Директивы
!$OMP CRITICAL[имя]
   блок операторов
!$OMP END CRITICAL[имя]
определяют критическую секцию (критическую область) – блок, операторы которого не должны выполняться одновременно двумя и более нитями. "Имя", если оно имеется, идентифицирует соответствующую критическую секцию. Директивы могут использоваться, например, для обновления общих переменных.
Директива
!$OMP BARIER
определяет точку синхронизации. При достижении данной точки выполнение нити приостанавливается. Нить продолжает выполнение лишь после достижения данной точки всеми нитями.
Директива
!$OMP ATOMIC
запрещает различным нитям одновременное обновление общей переменной, используемой в левой части следующего за данной директивой оператора присваивания.
Пример 3
!$OMP ATOMIC
   A(INDEX(I)= A(INDEX(I)) + B(I)
Директивы
!$OMP ORDERED
   блок операторов
!$OMP END ORDERED
определяют блок внутри параллельного цикла, операторы которого должны выполняться в том порядке, в котором итерации следуют в последовательном цикле
Директива
!$OMP FLUSH[(список переменных)]
определяет точку, в которой должно быть обеспечено согласованное между нитями состояние тех переменных, которые перечислены в списке. Неявно директива FLUSH присутствует в директивах BARRIER, CRITICAL, END CRITICAL, END DO, END PARALLEL, END SECTIONS, END SINGLE, ORDERED, END ORDERED.

Процедура синхронизации
OMP_INIT_LOCK(переменная)
выполняет создание и инициализация семафора (замка) с указанным именем; В качестве семафоров в OpenMP могут использоваться общие переменные типа INTEGER (их использование разрешено только в процедурах синхронизации).
Процедура
OMP_DESTROY_LOCK(переменная)
уничтожает семафор с указанным именем.
Процедура
OMP_SET_LOCK(переменная)
- вызывающая нить ждет освобождения семафора с указанным именем, а затем захватывает его.
Процедура
OMP_UNSET_LOCK(переменная)
вызывает освобождение семафора, захваченного вызывающей нитью.
Процедура
OMP_TEST_LOCK()
выполняет попытку захвата семафора (если семафор захвачен, функция возвращает FALSE).
Процедуры для запроса значений параметров среды исполнения.
Процедура
OMP_SET_NUM_THREADS(n)
устанавливает максимальное число нитей (n) в следующей за вызовом процедуры параллельной области (если это число разрешено менять динамически).
Процедура
MP_GET_MAX_THREADS()
возвращает максимальное возможное число нитей.
Процедура
MP_GET_NUM_THREADS()
возвращает фактическое число нитей в параллельной области.
Процедура
MP_GET_NUM_PROCS()
возвращает число доступных процессоров.
Процедура
OMP_IN_PARALLEL()
возвращает значение TRUE, если вызов процедуры произведен из параллельной области программы, и FALSE – в противном случае.
Процедура
OMP_SET_DYNAMIC(скалярное логическое выражение)
устанавливает состояние флага, разрешающего динамически изменять число нитей.
Процедура
OMP_GET_DYNAMIC()
запрашивает состояние флага, разрешающего динамически изменять число нитей.
Процедура
OMP_SET_NESTED(скалярное логическое выражение)
устанавливает состояние флага, разрешающего вложенный параллелизм.
Процедура
OMP_GET_NESTED(скалярное логическое выражение)
– если значение указанного логического выражения есть TRUE, то процедура устанавливает состояние флага, разрешающего вложенный параллелизм; если это значение равно FALSE, то процедура устанавливает состояние флага, запрещающего вложенный параллелизм.
Параметры окружения.
В целях создания переносимой среды запуска параллельных программ, в OpenMP определен ряд параметров окружения (переменных среды), позволяющих контролировать из OpenMP-программы поведение приложения.
Параметр
OMP_SCHEDULE
определяет способ распределения итераций в цикле, если в директиве DO использована спецификация SCHEDULE (RUNTIME).
Параметр
OMP_NUM_THREADS
определяет число нитей для исполнения параллельных областей приложения.
Параметр
OMP_DYNAMIC
разрешает или запрещает динамическое изменение числа нитей.
Параметр
OMP_NESTED
разрешает или запрещает вложенный параллелизм.
Рассмотренные выше средства OpenMP относятся к первой версии стандарта OpenMP, ориентированной на Фортран 77. В настоящее время имеется вторая версия стандарта OpenMP, ориентированная на Фортран 95. Отличия этих двух версий незначительны. Отметим лишь наличие во второй версии двух процедур для работы с таймером.
Имеется также спецификация OpenMP для языков C, C++. Спецификация содержит в функциональность, в основном аналогичную рассмотренной. Отметим лишь, что вместо специальных комментариев !$OMP используются директивы компилятора #pragma omp.