Понятие параллельной программы
Под параллельной программой в
рамках OpenMP
понимается программа, для которой в специально указываемых при помощи директив
местах – параллельных фрагментах– исполняемый программный код может быть
разделен на несколько раздельных потоков (threads). В общем виде программа
представляется в виде набора последовательных (однопотоковых) и
параллельных (многопотоковых) участков программного кода.
Важно отметить, что разделение вычислений между потоками осуществляется
под управлением соответствующих директив OpenMP. Равномерное распределение
вычислительной нагрузки – балансировка (load balancing) – имеет принципиальное
значение для получения максимально возможного ускорения выполнения параллельной
программы.
Потоки могут выполняться на разных процессорах (процессорных ядрах), либо
могут группироваться для исполнения на одном вычислительном элементе (в этом
случае их исполнение осуществляется в режиме разделения времени). В предельном
случае для выполнения параллельной программы может использоваться один процессор
– как правило, такой способ применяется для начальной проверки правильности
параллельной программы.
Количество потоков
определяется в момент создания параллельной секции и по умолчанию совпадает с
количеством определяемых операционной системой вычислительных элементов;
изменение количества создаваемых потоков может быть выполнено при помощи
специальных средств OpenMP. Все потоки параллельной секции
последовательно перенумерованы от 0 до np-1, где
np есть общее количество потоков в команде. Номер
потока также может быть получен при помощи функции OpenMP.
Использование в технологии OpenMP потоков
для организации параллелизма позволяет использовать преимущества многопроцессорных
вычислительных систем с общей памятью. Прежде всего, потоки одной и той же
параллельной программы выполняются в общем адресном пространстве, что
обеспечивает возможность использования общих данных для параллельно выполняемых
потоков без необходимости передачи сообщений (в отличие от процессов в
технологии MPI для систем с распределенной памятью). И, кроме того,
управление потоками (создание, приостановка, активизация, завершение) требует
меньше накладных расходов для ОС по сравнению с процессами.
Организация взаимодействия параллельных потоков
Как уже отмечалось ранее, потоки исполняются в общем адресном
пространстве программы. Как результат, взаимодействие потоков в параллельной
программе можно организовать через использование общих данных, которые доступные
всем потокам. Наиболее простая ситуация состоит в использовании общих данных
только для чтения. В случае же, когда общие данные могут изменяться несколькими
потоками, необходимы специальные усилия для организации правильного
взаимодействия. На самом деле, пусть два потока исполняют один и тот же
программный код
n=n+1;
для общей переменной n. Тогда в зависимости от
условий выполнения данная операция может быть выполнена поочередно (что приведет
к получению правильного результата) или же оба потока могут одновременно
прочитать значение переменной n, одновременно увеличить
и записать в эту переменную новое значение (как результат, будет получено
неправильное значение). Подобная ситуация, когда результат вычислений зависит от
темпа выполнения потоков, получил наименование гонки данных (race conditions). Для исключения гонки
необходимо, чтобы изменение значений общих переменных осуществлялось в каждый
момент времени только одним единственным потоком – иными словами необходимо
обеспечить взаимное исключение (mutual exclusion) потоков при работе с
общими данными. В OpenMP
взаимоисключение может быть организовано при помощи неделимых (atomic) операций, механизма критических секций (critical sections) или специального типа
семафоров – замков (locks).
Следует отметить, что организация взаимного исключения приводит к
уменьшению возможности параллельного выполнения потоков – при организации
взаимного исключения для доступа к общим переменным только один из них может
продолжить работу, все остальные потоки блокируются и ожидают освобождения общих
данных. Можно сказать, что именно при реализации взаимодействия потоков
проявляется искусство параллельного программирования для вычислительных систем с
общей памятью – организация взаимного исключения при работе с общими данными
является обязательной, но возникающие при этом задержки (блокировки) потоков
должны быть минимальными по времени.
Помимо взаимоисключения, при параллельном выполнении программы во многих
случаях является необходимым та или иная синхронизация (synchronization) вычислений,
выполняемых в разных потоках: например, обработка данных, выполняемая в одном
потоке, может быть начата только после того, как эти данные будут сформированы в
другом потоке (классическая задача параллельного программирования "производитель-потребитель" – "producer-consumer" problem). В OpenMP
синхронизация также может быть обеспечена при специальных
средств.
Структура OpenMP
Конструктивно в
составе технологии OpenMP можно
выделить:
-
Директивы,
-
Библиотеку функций,
-
Набор переменных окружения.
Формат директив OpenMP
Стандарт
предусматривает использование OpenMP для алгоритмических языков C90, C99, C++,
Fortran 77, Fortran 90 и Fortran 95. Далее описание формата директив OpenMP и
все приводимые примеры программ будут представлены на алгоритмическом языке C.
В самом общем виде формат директив OpenMP может
быть представлен в следующем виде:
#pragma omp <имя_директивы
> [<параметр
>[[,] <параметр
>]…]
Начальная часть директивы (#pragma omp) является фиксированной,
вид директивы определяется ее именем (имя_директивы),
каждая директива может сопровождаться произвольным количеством параметров (на
английском языке для параметров директивы OpenMP
используется термин clause).
Для иллюстрации приведем пример директивы:
#pragma omp parallel
default(shared) \
private(beta,pi)
Пример показывает также, что для задания директивы может быть
использовано несколько строк программы – признаком наличия продолжения является
знак обратного слеша "\".
Действие директивы
распространяется, как правило, на следующий в программе оператор, который может
быть, в том числе, и структурированным блоком.