В этом документе указана коллекция директив компилятора, функций библиотеки и переменных среды, которые можно использовать для указания параллелизма с общей памятью в программах C и C++. Функциональные возможности, описанные в этом документе, в совокупности называются интерфейсом программы (API) OpenMP C/C++. Цель этой спецификации — предоставить модель для параллельного программирования, которая позволяет переносить программу в архитектуры с общей памятью от разных поставщиков. Компиляторы от многих поставщиков поддерживают API OpenMP C/C++. Дополнительные сведения о OpenMP, включая интерфейс программы приложений OpenMP Fortran, можно найти на следующем веб-сайте:
Директивы, функции библиотеки и переменные среды, определенные в этом документе, позволяют создавать параллельные программы и управлять ими, обеспечивая при этом переносимость. Директивы расширяют модель последовательного программирования на C и C++ с помощью конструкций SPMD, конструкций совместного доступа к работе и конструкций синхронизации. Они также поддерживают обмен данными и их приватизацию. Компиляторы, поддерживающие API OpenMP C и C++, включают параметр командной строки для компилятора, который активирует и разрешает интерпретацию всех директив компилятора OpenMP.
Параллельное программирование: OpenMP
1.1 Область
Эта спецификация охватывает только параллелизацию, направленную на пользователя, при которой вы явно определяете действия, которые компилятор и система времени выполнения выполняют для параллельного выполнения программы. Реализации OpenMP C и C++ не требуются для проверка зависимостей, конфликтов, взаимоблокировок, состояний гонки или других проблем, которые приводят к неправильному выполнению программы. Вы отвечаете за правильное выполнение приложения, использующего конструкции API OpenMP C и C++. В этом документе не рассматриваются автоматические параллелизации, созданные компилятором, и директивы для компилятора, которые помогают в такой параллелизации.
1.2 Определение терминов
В этом документе используются следующие термины:
- barrier Точка синхронизации, которую должны достичь все потоки в команде. Каждый поток ожидает, пока все потоки в команде не придут на этот момент. Существуют явные барьеры, определенные директивами, и неявные барьеры, созданные реализацией.
- construct Конструкция — это оператор . Он состоит из директивы , за которой следует структурированный блок. Некоторые директивы не являются частью конструкции. (См. директиву openmp вприложении C).
- директива C или C++ #pragma с идентификатором omp , другим текстом и новой строкой. Директива задает поведение программы.
- динамический экстент Все операторы в лексической экстенте, а также любой оператор внутри функции, которая выполняется в результате выполнения операторов в лексическом экстенте. Динамический экстент также называется регионом.
- лексический экстент Операторы, лексически удерживаемые в структурированном блоке.
- поток master Поток, который создает команду при входе в параллельный регион .
- параллельный регион Операторы, которые привязываются к параллельной конструкции OpenMP и могут выполняться многими потоками.
- private Частная переменная присваивает имя блоку хранилища, уникальному для потока, создающего ссылку. Существует несколько способов указать, что переменная является частной: определение в параллельной области, директива threadprivate private , предложение , firstprivate , lastprivate , или reduction или использование переменной в качестве переменной управления циклом for в цикле for , сразу после for директивы или parallel for .
- region Динамический экстент.
- последовательный регион Инструкции, выполняемые только потоком master за пределами динамического экстента любого параллельного региона.
- serialize Выполнение параллельной конструкции с помощью:
- группа потоков, состоящая только из одного потока (который является master потоком для этой параллельной конструкции);
- последовательный порядок выполнения инструкций в структурированном блоке (такой же порядок, как если бы блок не был частью параллельной конструкции) и
- не влияет на значение, возвращаемое методом omp_in_parallel() (за исключением эффектов любых вложенных параллельных конструкций).
1.3. Модель выполнения
OpenMP использует модель вилки и соединения параллельного выполнения. Хотя эта модель соединения вилки может быть полезна для решения различных задач, она адаптирована для приложений на основе больших массивов. OpenMP предназначен для поддержки программ, которые правильно выполняются как параллельные программы (многие потоки выполнения и полная библиотека поддержки OpenMP).
OpenMP
Он также используется для программ, которые правильно выполняются как последовательные программы (директивы игнорируются и простая библиотека заглушек OpenMP). Однако при последовательном выполнении можно и разрешено разрабатывать программу, которая ведет себя неправильно. Кроме того, различные степени параллелизма могут привести к разным числовым результатам из-за изменений в связи с числовыми операциями. Например, сокращение последовательного сложения может иметь другой шаблон ассоциаций сложения, чем параллельное сокращение. Эти различные связи могут изменить результаты сложения с плавающей запятой.
Программа, написанная с помощью API OpenMP C/C++, начинает выполнение в виде одного потока выполнения, называемого потоком master. Поток master выполняется в последовательной области, пока не будет обнаружена первая параллельная конструкция. В API OpenMP C/C++ директива parallel представляет собой параллельную конструкцию.
При обнаружении параллельной конструкции поток master создает группу потоков, а master становится master команды. Каждый поток в команде выполняет инструкции в динамическом экстенте параллельной области, за исключением конструкций совместного использования работы. Все потоки в команде должны встречаться с конструкциями совместного использования работы в одном порядке, и один или несколько потоков выполняют инструкции в связанном структурированном блоке. Барьер, подразумеваемый в конце конструкции совместного использования работы без nowait предложения, выполняется всеми потоками в команде.
Если поток изменяет общий объект, он влияет не только на собственную среду выполнения, но и на другие потоки в программе. Изменение гарантированно будет завершено с точки зрения другого потока в следующей точке последовательности (как определено в базовом языке) только в том случае, если объект объявлен переменным. В противном случае изменение гарантированно будет завершено после первого изменения потока. Затем другие потоки (или одновременно) видят директиву flush , которая указывает объект (неявно или явно). flush Если директивы, подразумеваемые другими директивами OpenMP, не гарантируют правильное упорядочение побочных эффектов, программист несет ответственность за предоставление дополнительных явных flush директив.
После завершения параллельной конструкции потоки в команде синхронизируются на неявном барьере, и только поток master продолжает выполнение. В одной программе можно указать любое количество параллельных конструкций. В результате программа может много раз подтаять и объединяться во время выполнения.
API OpenMP C/C++ позволяет программистам использовать директивы в функциях, вызываемые из параллельных конструкций. Директивы, которые не отображаются в лексической экстенте параллельной конструкции, но могут лежать в динамическом экстенте, называются потерянными директивами. При использовании потерянных директив программисты могут выполнять основные части своей программы параллельно, при этом в последовательную программу внесены лишь минимальные изменения. С помощью этой функции можно кодировать параллельные конструкции на верхних уровнях дерева вызовов программы и использовать директивы для управления выполнением в любой из вызываемых функций.
Несинхронизированные вызовы выходных функций C и C++, которые записываются в один и тот же файл, могут привести к выводу данных, записанных разными потоками, в недетерминированном порядке. Аналогичным образом несинхронизированные вызовы входных функций, которые считывают данные из одного файла, могут считывать данные в недетерминированном порядке. Несинхронизированное использование операций ввода-вывода, так что каждый поток обращается к другому файлу, дает те же результаты, что и последовательное выполнение функций ввода-вывода.
1.4 Совместимость
Реализация API OpenMP C/C++ совместима с OpenMP , если она распознает и сохраняет семантику всех элементов этой спецификации, как описано в главах 1, 2, 3, 4 и Приложении C. Приложения A, B, D, E и F предназначены только для информационных целей и не являются частью спецификации. Реализации, включающие только подмножество API, не совместимы с OpenMP.
API OpenMP C и C++ — это расширение базового языка, поддерживаемого реализацией. Если базовый язык не поддерживает языковую конструкцию или расширение, которые отображаются в этом документе, реализация OpenMP не требуется для его поддержки.
Все стандартные функции библиотекИ C и C++ и встроенные функции (то есть функции, о которых компилятор обладает определенными знаниями) должны быть потокобезопасны. Несинхронизированное использование потокобезопасных функций разными потоками в параллельной области не приводит к неопределенному поведению. Однако поведение может не совпадать с поведением в последовательной области. (Примером является функция создания случайных чисел.)
API OpenMP C/C++ указывает, что определенное поведение определяется реализацией. Для определения и документирования ее поведения в этих случаях требуется соответствующая реализация OpenMP. Список поведений, определенных реализацией, см. в приложении E.
1.5 Нормативные ссылки
- ISO/IEC 9899:1999, Информационные технологии — Языки программирования — C. Эта спецификация API OpenMP ссылается на ISO/IEC 9899:1999 как C99.
- ISO/IEC 9899:1990, Информационные технологии — Языки программирования — C. Эта спецификация API OpenMP ссылается на ISO/IEC 9899:1990 как C90.
- ISO/IEC 14882:1998, Информационные технологии — языки программирования — C++. Эта спецификация API OpenMP ссылается на ISO/IEC 14882:1998 как C++.
Если эта спецификация API OpenMP ссылается на C, делается ссылка на базовый язык, поддерживаемый реализацией.
1.6 Организация
- Функции библиотеки среды выполнения
- Переменные среды
- Поведения, определяемые реализацией, в OpenMP C/C++
- Новые возможности OpenMP C/C++ версии 2.0
Источник: learn.microsoft.com
Параллельные заметки №1 – технология OpenMP
В ближайшие несколько постов мы расскажем о практическом использовании многоядерных процессоров. Ведь все-таки что бы ни говорилось о многоядерности, в любом случае программы надо «обучать» эффективному использованию нескольких ядер. А в этом первом посте будет анонс и первая «вводная» заметка.
Технологии параллельного программирования
Сразу же надо сказать, что существует довольно много разных технологий параллельного программирования. Причем эти технологии отличаются не только и не столько языками программирования, сколько архитектурными подходами к построению параллельных систем.
Например, какие-то технологии предполагают построение параллельных решений на основе нескольких компьютеров (как одного, так и разных типов), другие же предполагают именно работу на одной машине с несколькими процессорными ядрами.
Системы на базе нескольких компьютеров относят к классу систем для распределенных вычислений. Подобные решения используются довольно давно, их хорошо понимают профессионалы индустрии, по ним имеется довольно много литературы. Наиболее яркий пример технологии распределенных вычислений — MPI (Message Passing Interface — интерфейс передачи сообщений). MPI является наиболее распространённым стандартом интерфейса обмена данными в параллельном программировании, существуют его реализации для большого числа компьютерных платформ. MPI предоставляет программисту единый механизм взаимодействия ветвей внутри параллельного приложения независимо от машинной архитектуры (однопроцессорные/многопроцессорные с общей/раздельной памятью), взаимного расположения ветвей (на одном процессоре или на разных).
Так как MPI предназначен для систем с раздельной памятью, то использовать его для организации параллельного процесса в системе с общей памятью не лучшая идея. Это будет слишком избыточно и сложно, поэтому-то и начали развиваться решения вроде OpenMP. Хотя, конечно же, ничто не мешает делать MPI-решения для одной машины.
А вот системы параллельного программирования для работы на одной машине, начали развиваться относительно недавно. Нет, конечно же, не стоит думать, что это принципиально новые идеи, но именно с приходом (вернее с предстоящим приходом) многоядерных систем на рабочий стол, программистам стоит обратить свое внимание на такие технологии как OpenMP, Intel Thread Building Blocks, Microsoft Parallel Extensions и ряд других.
Очень важно, чтобы технология параллельного программирования поддерживала возможность делать программу параллельной постепенно. Да, понятно, что идеальную параллельную программу надо сразу писать параллельной, а еще лучше на каком-нибудь функциональном языке, где вопрос распараллеливания вообще не стоит… Но программисты живут и работают в реальном мире, в котором вместо новомодного функционального F# есть 10 МБайт кода в лучшем случае на C++, а то и вообще на C. И этот код надо постепенно распараллеливать.
В этом случае технология OpenMP (к примеру) будет очень удачным выбором. Она позволяет, выбрав в приложении наиболее нуждающиеся в параллелизации места, в первую очередь сделать параллельными именно их. На практике это выглядит так. С помощью какого-либо инструмента для профилирования программист ищет в программе «узкие места», которые работают наиболее долго.
Почему с помощью инструмента? Потому что силой мысли в малоизвестном проекте размером в 10 Мбайт найти «узкие места» не удастся. Затем эти узкие места программист делает параллельными с помощью OpenMP. После этого, можно искать следующие узкие места и так далее, до тех пор, пока не будет получена желаемая производительность приложения.
Процесс разработки параллельной версии можно прерывать, выпускать промежуточные релизы, возвращаться к нему по мере необходимости. Именно поэтому в частности технология OpenMP стала довольно популярной.
Что же такое OpenMP?
OpenMP (Open Multi-Processing) — это набор директив компилятора, библиотечных процедур и переменных окружения, которые предназначены для программирования многопоточных приложений на многопроцессорных системах с общей памятью (SMP-системах).
Первый стандарт OpenMP был разработан в 1997 г. как API, ориентированный на написание легко переносимых многопоточных приложений. Сначала он был основан на языке Fortran, но позднее включил в себя и языки Си и Си++.
Интерфейс OpenMP стал одной из наиболее популярных технологий параллельного программирования. OpenMP успешно используется как при программировании суперкомпьютерных систем с большим количеством процессоров, так и в настольных пользовательских системах или, например, в Xbox 360.
Разработку спецификации OpenMP ведут несколько крупных производителей вычислительной техники и программного обеспечения, чья работа регулируется некоммерческой организацией «OpenMP Architecture Review Board» (ARB).
В OpenMP используется модель параллельного выполнения «ветвление-слияние». Программа OpenMP начинается как единственный поток выполнения, называемый начальным потоком. Когда поток встречает параллельную конструкцию, он создает новую группу потоков, состоящую из себя и некоторого числа дополнительных потоков, и становится главным в новой группе.
Все члены новой группы (включая главный) выполняют код внутри параллельной конструкции. В конце параллельной конструкции имеется неявный барьер. После параллельной конструкции выполнение пользовательского кода продолжает только главный поток. В параллельный регион могут быть вложены другие параллельные регионы, в которых каждый поток первоначального региона становится основным для своей группы потоков. Вложенные регионы могут в свою очередь включать регионы более глубокого уровня вложенности.
Число потоков в группе, выполняющихся параллельно, можно контролировать несколькими способами. Один из них — использование переменной окружения OMP_NUM_THREADS. Другой способ — вызов процедуры omp_set_num_threads(). Еще один способ — использование выражения num_threads в сочетании с директивой parallel.
Анонс ближайших заметок по параллельному программированию
Этой записью мы начинаем небольшой цикл публикаций посвященных знакомству с технологией OpenMP и инструментарием для разработки параллельных приложений. В следующих заметках вы узнаете:
• какие инструменты нужны для разработки параллельных программ;
• как создать с нуля параллельную программу;
• как добавить в существующую программу параллельное выполнение с помощью технологии OpenMP;
• какие типовые проблемы возникают при разработке OpenMP –приложений и как их диагностировать;
• оптимизация параллельных программ.
Ждите следующего выпуска уроков, а в комментариях, пожалуйста, отпишите, какие темы параллельного программирования интересуют вас. И тогда мы будем делать дальнейшие заметки с учетом ваших пожеланий.
Дополнительные материалы
Источник: habr.com
Параллельное программирование в стандарте OpenMP
1. Параллельное программирование в стандарте OpenMP
М.Л. Цымблер
2. Содержание
Модель программирования в общей памяти
Модель FORK-JOIN
Стандарт OpenMP
Основные понятия и функции OpenMP
2
3. Программирование в общей памяти
Данные
…
Процесс 0
Процесс 1
Параллельное приложение
состоит из нескольких
процессов, выполняющихся
одновременно.
Процессы разделяют общую
память.
Обмены между процессами
осуществляются посредством
чтения/записи данных в
общей памяти.
Процессы могут выполняться
как на одном и том же, так и
на разных процессорах.
Процесс N-1
3
4. Модель FORK-JOIN
Сегмент стека
Главная нить (процесс)
main()
Сег. стека
нить
Сег. стека
…
нить
Сегмент данных
Fork
Нить
…
Нить
Join
Современные операционные
системы поддерживают
полновесные процессы
(программы) и легковесные
процессы (нити).
Процесс – главная нить.
Нить может запускать другие
нити в рамках процесса. Каждая
нить имеет собственный сегмент
стека.
Все нити процесса разделяют
сегмент данных процесса.
4
5. Стандарт OpenMP
OpenMP – стандарт, реализующий модели
программирования в общей памяти и Fork-Join.
Стандарт представляет собой набор директив
компилятора и спецификаций подпрограмм для
на языках C, С++ и FORTRAN.
Стандарт реализуется разработчиками
компиляторов для различных аппаратнопрограммных платформ (кластеры,
персональные компьютеры, …, Windows,
Unix/Linux, …).
5
6. Структура OpenMP-программы
Главная нить (программа) порождает семейство дочерних нитей
(сколько необходимо). Порождение и завершение
осуществляется с помощью директив компилятора.
Преобразование последовательной программы в параллельную
может происходить «инкрементно».
Последовательные регионы
Главная
нить
Нити
Параллельные регионы
6
7. Директивы OpenMP
Директивы OpenMP – директивы C/C++
компилятора #pragma.
Для
использования директив необходимо
установить соответствующие параметры
компилятора (обычно -openmp).
Синтаксис директив OpenMP:
#pragma omp имя_директивы [параметры]
Примеры:
#pragma omp parallel
#pragma omp for private(i, j) reduction(+: sum)
7
8. Функции библиотеки OpenMP
Назначение функций библиотеки:
контроль и просмотр параметров OpenMPпрограммы
явная синхронизация нитей на базе «замков»
omp_get_thread_num() возвращает номер текущей нити
omp_set_lock() устанавливает «замок»
Для использования функций необходимо
подключить библиотеку
#include
«omp.h»
8
9. Переменные окружения OpenMP
Переменные окружения контролируют
поведение приложения.
OMP_NUM_THREADS – количество нитей в параллельном
регионе
OMP_DYNAMIC – разрешение или запрет динамического
изменения количества нитей.
OMP_NESTED – разрешение или запрет вложенных
параллельных регионов.
OMP_SCHEDULE – способ распределения итераций в
цикле.
Функции назначения параметров изменяют значения
соответствующих переменных окружения.
9
10. Директивы определения параллельных фрагментов
#pragma omp parallel
Определяет блок кода, который будет выполнен всеми
созданными на входе в этот блок нитями.
#pragma omp for
Определяет цикл, итерации которого должны выполняться
одновременно несколькими нитями.
#pragma omp section
Определяет множество блоков кода, каждый из который будет
выполняться только одной из созданных на входе в этот блок
нитью.
#pragma omp master
Определяет блок кода, который будет выполнен только главной
нитью.
10
11. Простая программа на OpenMP
Последовательный код
void main()
printf(«Hello!n»);
>
Параллельный код
void main()
#pragma omp parallel
printf(«Hello!n»);
>
>
Результат
Результат
Hello!
Hello!
Hello!
(для 2-х нитей)
11
12. Директива parallel for
OpenMP поддерживает редукцию вычислительных операций,
выполняемых в циклах. Редукция подразумевает определение
для каждой нити частной переменной для вычисления
«частичного» результата и автоматическое выполнение
операции «слияния» частичных результатов.
#pragma omp parallel for reduction(+:sum)
for (i=0; i sum += a[i] * b[i];
>
Операция
Нач. значение
+
0
*
1
—
0
^
0
#pragma omp section
phase2();
#pragma omp section
phase3();
>
Послед.
Паралл.
13
14. Область видимости переменных
Общая переменная (shared) – доступна для
модификации всем нитям.
Частная переменная (private) – доступна для
модификации только одной (создавшей ее)
нити только на время выполнения этой нити.
Правила видимости переменных:
все переменные, определенные вне параллельной
области – общие;
все переменные, определенные внутри
параллельной области – частные.
14
15. Общие и частные переменные
void main()
int a, b, c;
…
#pragma omp parallel
int d, e;
…
>
>
Общие
Частные
15
16. Явное указание области видимости
Для явного указания области видимости
используются следующие параметры директив:
shared() – общие переменные
private() – частные переменные
Примеры:
#pragma omp parallel shared(buf)
#pragma omp for private(i, j)
16
17. Общие и частные переменные
void main()
Общие
int a, b, c;
…
#pragma omp parallel shared(a) private(b)
int d, e;
Частные
…
>
>
17
18. Общие и частные переменные
void main()
int rank;
#pragma omp parallel
rank = omp_get_thread_num();
>
printf(«%dn», rank);
>
void main()
int rank;
#pragma omp parallel
rank = omp_get_thread_num();
printf(«%dn», rank);
>
>
18
19. Общие и частные переменные
void main()
int rank;
#pragma omp parallel shared
(rank)
rank = omp_get_thread_num();
printf(«%dn», rank);
>
>
void main()
int rank;
#pragma omp parallel private
(rank)
rank = omp_get_thread_num();
printf(«%dn», rank);
>
>
19
20. Директивы синхронизации
#pragma omp master
Определяет блок кода, который будет выполнен только главной
нитью.
#pragma omp critical
Определяет блок кода, который не должен выполняться
одновременно двумя или более нитями.
#pragma omp barrier
Определяет точку барьерной синхронизации, в которой каждая
нить дожидается всех остальных.
#pragma omp atomic
Определяет переменную в левой части оператора «атомарного»
присваивания, которая должна корректно обновляться
несколькими нитями.
#pragma omp flush
Явно определяет точку, в которой обеспечивается одинаковый
вид памяти для всех нитей.
20
21. #pragma omp master
Определяет блок кода, который будет выполнен
только главной нитью. Не подразумевает барьера для
других нитей.
#pragma omp parallel
DoSomeJob1(omp_get_thread_num());
#pragma master
printf(«Job #1 donen»);
>
DoSomeJob2(omp_get_thread_num());
#pragma master
printf(«Job #2 donen»);
>
>
21
22. #pragma omp critical
Определяет блок кода, который не должен
выполняться одновременно двумя или более нитями.
float dot_prod(float* a, float* b, int N)
float sum = 0.0;
#pragma omp parallel for shared(sum)
for (i=0; i
>
return sum;
>
float dot_prod(float* a, float* b, int N)
float sum = 0.0;
#pragma omp parallel for shared(sum)
for (i=0; i
sum += a[i] * b[i];
>
return sum;
>
22
Источник: ppt-online.org