Для создания параллельных программ в openmp используется следующая модель программирования

Обновлено: 02.07.2024

Указывает, что область памяти будет обновляться атомарно.

Параметры

выражение
Инструкция с lvalue, место в памяти которого вы хотите защитить от более чем одной записи.

Примечания

Директива atomic не поддерживает никаких предложений.

Пример

барьер

Синхронизирует все потоки в команде; все потоки приостанавливаются на барьере, пока все потоки не выполнят барьер.

Примечания

Директива барьера не поддерживает никаких предложений.

Пример

Пример использования барьера см. в мастер-классе.

критично

Указывает, что код должен выполняться только в одном потоке за раз.

Параметры

имя
(необязательно) Имя для идентификации критического кода. Имя должно быть заключено в круглые скобки.

Примечания

Директива Critical не поддерживает никаких предложений.

Пример

смыть

Указывает, что все потоки имеют одинаковое представление памяти для всех общих объектов.

Параметры

var
(Необязательно) Список переменных, разделенных запятыми, которые представляют объекты, которые вы хотите синхронизировать. Если var не указан, сбрасывается вся память.

Примечания

Директива flush не поддерживает никаких предложений.

Пример

Приводит к тому, что работа, выполняемая в цикле for внутри параллельной области, распределяется между потоками.

Параметры

предложения
(Необязательно) Ноль или более предложений, см. раздел "Примечания".

for_statement
Цикл for. Если пользовательский код в цикле for изменит индексную переменную, возникнет неопределенное поведение.

Примечания

Директива for поддерживает следующие предложения:

Если параметр parallel также указан, предложениями могут быть любые предложения, принимаемые директивами parallel или for, за исключением nowait .

Для получения дополнительной информации см. 2.4.1 для конструкции.

Пример

мастер

Указывает, что только главный поток должен выполнять часть программы.

Примечания

Главная директива не поддерживает никаких предложений.

Директива single позволяет указать, что часть кода должна выполняться в одном потоке, не обязательно в главном потоке.

Пример

заказано

Указывает, что код в параллельном цикле for должен выполняться как последовательный цикл.

Примечания

Директива order должна находиться в пределах динамического экстента конструкции for или parallel for с предложениемordered.

Директива order не поддерживает никаких предложений.

Пример

параллельно

Определяет параллельную область, то есть код, который будет выполняться несколькими потоками параллельно.

Параметры

предложения
(Необязательно) Ноль или более предложений, см. раздел "Примечания".

Примечания

Директива parallel поддерживает следующие пункты:

parallel также можно использовать с директивами for и section.

Пример

В следующем примере показано, как задать количество потоков и определить параллельную область. Количество потоков по умолчанию равно количеству логических процессоров на машине. Например, если у вас есть машина с одним физическим процессором, на котором включена технология Hyper-Threading, она будет иметь два логических процессора и два потока. Порядок вывода может различаться на разных машинах.

разделы

Определяет разделы кода, которые нужно разделить между всеми потоками.

Параметры

предложения
(Необязательно) Ноль или более предложений, см. раздел "Примечания".

Примечания

Директива section может содержать ноль или более директив section.

Директива разделов поддерживает следующие пункты:

Если параметр parallel также указан, предложениями могут быть любые предложения, принимаемые директивами parallel или section, за исключением nowait .

Пример

один

Позволяет указать, что часть кода должна выполняться в одном потоке, не обязательно в главном потоке.

Параметры

предложения
(Необязательно) Ноль или более предложений, см. раздел "Примечания".

Примечания

Директива single поддерживает следующие пункты:

Директива master позволяет указать, что часть кода должна выполняться только в главном потоке.

Пример

приватный поток

Указывает, что переменная является частной для потока.

Параметры

var
Список переменных, разделенных запятыми, которые вы хотите сделать частными для потока. var должна быть либо глобальной переменной, либо областью видимости пространства имен, либо локальной статической переменной.

Примечания

Директива threadprivate не поддерживает никаких предложений.

Директива threadprivate основана на атрибуте потока с использованием ключевого слова __declspec; ограничения на __declspec(thread) применяются к threadprivate .Например, переменная threadprivate будет существовать в любом потоке, запущенном в процессе, а не только в тех потоках, которые являются частью группы потоков, порожденной параллельным регионом. Помните об этой детали реализации; вы можете заметить, что конструкторы для пользовательского типа threadprivate вызываются чаще, чем ожидалось.

Вы можете использовать threadprivate в библиотеке DLL, которая статически загружается при запуске процесса, однако вы не можете использовать threadprivate в любой библиотеке DLL, которая будет загружаться через LoadLibrary, например в библиотеках DLL, загружаемых с параметром /DELAYLOAD (отложенный импорт загрузки), что также использует LoadLibrary .

Для переменной threadprivate типа destructible не гарантируется вызов деструктора. Например:

Пользователи не могут контролировать, когда потоки, составляющие параллельный регион, будут завершены. Если эти потоки существуют, когда процесс завершается, потоки не будут уведомлены о завершении процесса, и деструктор не будет вызываться для threaded_var ни в одном потоке, кроме того, который выходит (здесь основной поток). Поэтому код не должен рассчитывать на правильное уничтожение переменных threadprivate.

OpenMP — это библиотека, поддерживающая многопроцессорную обработку совместно используемой памяти. Модель программирования OpenMP — это SMP (симметричные мультипроцессоры или процессоры с общей памятью): это означает, что при программировании с помощью OpenMP все потоки совместно используют память и данные.

Параллельный код с метками OpenMP, посредством специальной директивы, секции должны выполняться параллельно. Часть кода, помеченная для параллельного выполнения, вызовет формирование потоков. Основной протектор является основной нитью. Все подчиненные потоки работают параллельно и выполняют один и тот же код. Каждый поток выполняет распараллеленный участок кода независимо. Когда поток завершается, он присоединяется к мастеру. Когда все потоки завершены, мастер продолжает код, следующий за параллельным разделом.

Каждый поток имеет прикрепленный к нему идентификатор, который можно получить с помощью функции библиотеки времени выполнения (называемой omp_get_thread_num()). Идентификатор главного потока равен 0.

OpenMP поддерживает C, C++ и Fortran.

Функции OpenMP включены в заголовочный файл с именем

  • указать параллельную область (создать потоки)
  • указать, как распараллелить циклы
  • указать область действия переменных в параллельном разделе (частные и общие)
  • укажите, должны ли потоки быть синхронизированы
  • указать, как работа распределяется между потоками (планирование)

Компиляция и запуск кода OpenMP

На общедоступных Linux-компьютерах Dover и Foxcroft установлены gcc/g++ с поддержкой OpenMP. Все, что вам нужно сделать, это использовать флаг -fopenmp в командной строке:

Указание параллельной области (создание потоков)

Пример (программа C): Отобразите "Hello, world". с использованием нескольких потоков. Используйте флаг -fopenmp для компиляции с использованием gcc: Вывод на компьютере с двумя ядрами и, следовательно, с двумя потоками: В Дувре я получил 24 приветствия для 24 потоков. На моем рабочем столе я получаю (только) 8. Сколько вы получаете?

Обратите внимание, что все потоки записывают данные в стандартный вывод, и существует гонка за их совместное использование. Способ чередования потоков совершенно произвольный, и вы можете получить искаженный вывод:

Частные и общие переменные

  • общие: данные в параллельном регионе являются общими, что означает видимость и доступность для всех потоков одновременно. По умолчанию все переменные в области совместной работы являются общими, кроме счетчика итераций цикла.
  • private: данные в параллельном регионе являются частными для каждого потока, что означает, что каждый поток будет иметь локальную копию и использовать ее как временную переменную. Частная переменная не инициализируется, и ее значение не сохраняется для использования за пределами параллельной области. По умолчанию счетчики итераций цикла в конструкциях цикла OpenMP являются закрытыми.

Пример: иногда вам нужно совместное использование переменных, а иногда нет, и это может привести к возникновению условий гонки. Другими словами, некоторые переменные должны быть общими, некоторые должны быть частными, и вы, программист, должны указать, что вы хотите.

Синхронизация

  • критично: вложенный блок кода будет выполняться только одним потоком за раз, а не одновременно несколькими потоками. Он часто используется для защиты общих данных от условий гонки.
  • omp_get_num_threads
  • omp_get_num_procs
  • omp_set_num_threads
  • omp_get_max_threads

Распараллеливание циклов

Распараллелить циклы с помощью OpenMP очень просто. Один просто обозначает цикл, который нужно распараллелить, и несколько параметров, а OpenMP позаботится обо всем остальном. Проще не бывает!

Планирование циклов

Более сложные директивы

  • можно определять «разделы» внутри параллельного блока
  • может запросить, чтобы итерации цикла выполнялись по порядку
  • указать блок, который будет выполняться только главным потоком
  • указать блок, который будет выполняться только первым достигшим его потоком
  • определить раздел как «критический»: будет выполняться каждым потоком, но может выполняться только одним потоком за раз. Это заставляет потоки чередоваться, а не прерывать друг друга.
  • определить секцию как «атомарную»: это заставляет потоки выполнять запись в разделяемую память последовательно, чтобы избежать условий гонки.

Вопросы производительности

Критические секции и атомарные секции сериализуют выполнение и исключают параллельное выполнение потоков. При неразумном использовании код OpenMP может быть хуже последовательного кода из-за накладных расходов на потоки.

Некоторые комментарии

OpenMP — это не волшебство. Цикл должен быть явно распараллелен, чтобы OpenMP мог его развернуть и упростить распределение итераций между потоками. Если есть какие-либо зависимости данных от одной итерации к другой, OpenMP не может их распараллелить.

Цикл for не может завершиться досрочно, например: значения выражений управления циклом должны быть одинаковыми для всех итераций цикла. Например:

Поскольку Summit представляет собой кластер ЦП, наиболее эффективным способом использования этих ресурсов является параллельное программирование. Вероятно, самым простым способом начать параллельное программирование является использование OpenMP. OpenMP — это решение на стороне компилятора для создания кода, работающего на нескольких ядрах/потоках. Поскольку OpenMP встроен в компилятор, для компиляции этого кода не требуется устанавливать внешние библиотеки. В этих руководствах содержатся основные инструкции по использованию OpenMP как в компиляторе GNU C++, так и в компиляторе Intel C++.

В этом руководстве предполагается, что у вас есть базовые знания о командной строке и языке C++.

Более подробное руководство по OpenMP и MPI C++:

Параллельная программа «Hello, World»¶

В этом разделе мы узнаем, как создать простую параллельную программу hello world на C++. Начнем с создания программы под названием: parallel_hello_world.cpp. В командной строке выполните команду:

Мы начнем с операторов включения, которые должны выполняться в верхней части программы:

Эти флаги позволяют нам использовать библиотеки stdio и omp в нашей программе. Заголовочный файл будет обеспечивать функциональность openmp. Заголовочный файл предоставит нам возможность печати.

Давайте теперь начнем нашу программу с построения основной функции программы. Мы будем использовать omp_get_thread_num() для получения идентификатора потока процесса. Это позволит нам идентифицировать каждый из наших потоков, используя этот уникальный идентификатор.

Давайте скомпилируем наш код и посмотрим, что получится. Мы должны сначала загрузить нужный модуль компилятора в нашу среду. Мы можем сделать это следующим образом:

ССЗ:

В командной строке, где находится ваш код, выполните команду:

ССЗ:

Это даст нам исполняемый файл, который мы можем запустить в качестве задания для Summit. Просто запустите задание, указав slurm, чтобы запустить исполняемый файл. Ваш сценарий задания должен выглядеть примерно так:

Наш выходной файл должен выглядеть так:

Мы должны сделать еще кое-что, прежде чем добиться распараллеливания. Чтобы установить количество потоков, в которых мы хотим запускать OpenMP, мы должны установить переменную среды Linux, чтобы указать, сколько потоков мы хотим использовать. Переменная среды: OMP_NUM_THREADS сохранит эту информацию. Изменение этой переменной не требует перекомпиляции программы, поэтому эту команду можно разместить либо в командной строке, либо в вашем скрипте задания:

Важно отметить: эту переменную среды нужно будет устанавливать каждый раз, когда вы выходите из оболочки. Если вы хотите сделать это изменение постоянным, вам нужно будет добавить эти строки в ваш файл .bash_profile в вашем домашнем каталоге:

Теперь давайте перекомпилируем код и запустим его, чтобы посмотреть, что получится:

ССЗ

Интел

Запуск нашего скрипта задания, и мы должны закончить с выходным файлом, подобным этому:

Не беспокойтесь о порядке распечатки процессов, потоки будут распечатываться в разное время.

Личные и общие переменные¶

Управление памятью – это основной компонент любой параллельной программы, в которой используются операции с данными. В этом разделе мы узнаем о различных типах переменных в OpenMP, а также о простой реализации этих типов в программе, которую мы создали в предыдущем разделе.

OpenMP имеет множество инструментов, которые можно использовать для правильного описания того, как параллельная программа должна обрабатывать переменные. Эти инструменты представлены в виде общих и частных классификаторов типов переменных.

  • Частные типы создают копию переменной для каждого процесса в параллельной системе.
  • Общие типы содержат один экземпляр переменной для совместного использования всеми процессами.

Чтобы указать частную или общую память, объявите переменную перед разделом parallel и аннотируйте директиву pragma omp как таковую:

Переменные, созданные и назначенные внутри параллельного раздела кода, по своей сути будут частными, а переменные, созданные вне параллельных разделов, будут по своей сути общедоступными.

Пример¶

Давайте адаптируем наш код Hello World, чтобы в качестве примера использовать закрытые переменные. Начнем с кода, на котором мы остановились, давайте создадим переменную для хранения идентификатора потока каждого процесса.

Теперь давайте определим thread_id как приватную переменную. Поскольку мы хотим, чтобы каждая задача имела уникальный идентификатор потока, использование private(thread_id) создаст отдельный экземпляр thread_id для каждой задачи.

Наконец, давайте назначим идентификатор потока нашей частной переменной и распечатаем переменную вместо вызова функции omp_get_thread_num():

Компиляция и запуск нашего кода приведет к результату, аналогичному нашему исходному hello world:

Барьеры и критические директивы¶

OpenMP имеет множество инструментов для управления процессами. Одна из наиболее известных форм контроля связана с барьером:

…и важные директивы:

Директива барьера останавливает все процессы для перехода к следующей строке кода, пока все процессы не достигнут барьера. Это позволяет программисту синхронизировать последовательности в параллельном процессе.

Критическая директива гарантирует, что строка кода запускается только одним процессом за раз, что обеспечивает безопасность потоков в теле кода.

Пример¶

Давайте реализуем барьер OpenMP, заставив нашу программу «Hello World» печатать свои процессы по порядку. Начиная с кода, который мы создали в предыдущем разделе, давайте вложим наш оператор печати в цикл, который будет повторяться от 0 до максимального количества потоков. Мы получим максимальное количество потоков, используя функцию OpenMP: omp_get_max_threads()

Наша программа Hello World теперь будет выглядеть так:

Теперь, когда цикл создан, давайте создадим условие, требующее, чтобы цикл находился на правильной итерации для вывода номера потока:

Наконец, чтобы гарантировать, что один процесс не опережает другой, нам нужно добавить в код директиву барьера. Давайте реализуем один из них в нашем цикле:

Компиляция и запуск нашего кода должны упорядочивать наши операторы печати следующим образом:

Директива о совместной работе: omp for¶

Преимущество OpenMP заключается в простом разделении большой задачи на несколько более мелких задач. Директивы разделения работы позволяют просто и эффективно разбивать обычно последовательные задачи на быстрые параллельные участки кода. В этом разделе мы узнаем, как реализовать директиву omp for.

Директива omp for делит обычно последовательный цикл for на параллельную задачу. Мы можем реализовать эту директиву как таковую:

Пример¶

Давайте напишем программу для сложения всех чисел от 1 до 1000. Начнем с функции main и заголовков stdio и omp:

Теперь давайте настроим переменные для нашего параллельного кода. Давайте сначала создадим переменные partial_Sum и total_Sum для хранения частичного суммирования каждого потока и общей суммы всех потоков соответственно.

Далее давайте начнем наш параллельный раздел с прагмы omp parallel . Мы также установим partial_Sum как частную переменную, а total_Sum как общую переменную. Мы будем инициализировать каждую переменную в параллельной секции.

Это завершит наше параллельное суммирование. Компиляция и запуск нашего кода приведет к следующему результату:

В этом документе указан набор директив компилятора, библиотечных функций и переменных среды, которые можно использовать для указания параллелизма с общей памятью в программах C и C++. Функциональные возможности, описанные в этом документе, известны под общим названием интерфейс прикладной программы OpenMP C/C++ (API). Цель этой спецификации — предоставить модель параллельного программирования, которая позволяет программе быть переносимой между архитектурами с общей памятью от разных поставщиков. Компиляторы многих производителей поддерживают OpenMP C/C++ API. Дополнительную информацию об OpenMP, включая интерфейс прикладной программы OpenMP Fortran, можно найти на следующем веб-сайте:

Директивы, библиотечные функции и переменные среды, определенные в этом документе, позволяют создавать параллельные программы и управлять ими, обеспечивая переносимость. Эти директивы расширяют модель последовательного программирования C и C++ конструкциями с одной программой и несколькими данными (SPMD), конструкциями для совместной работы и конструкциями синхронизации. Они также поддерживают совместное использование и приватизацию данных. Компиляторы, поддерживающие API OpenMP C и C++, включают параметр командной строки для компилятора, который активирует и позволяет интерпретировать все директивы компилятора OpenMP.

1.1 Область применения

Эта спецификация охватывает только параллелизацию, управляемую пользователем, при которой вы явно определяете, какие действия компилятор и система выполнения выполняют для параллельного выполнения программы.Реализации OpenMP C и C++ не обязаны проверять наличие зависимостей, конфликтов, взаимоблокировок, состояний гонки или других проблем, которые приводят к неправильному выполнению программы. Вы несете ответственность за правильное выполнение приложения, использующего конструкции OpenMP C и C++ API. Создаваемое компилятором автоматическое распараллеливание и директивы для компилятора, помогающие такому распараллеливанию, в этом документе не рассматриваются.

1.2 Определение терминов

В этом документе используются следующие термины:

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

Конструкция — это оператор. Он состоит из директивы, за которой следует структурированный блок. Некоторые директивы не являются частью конструкции. (См. директиву openmp в приложении C).

Все операторы в лексическом экстенте, а также любые операторы внутри функции, которая выполняется в результате выполнения операторов в пределах лексического экстента. Динамический экстент также называется регионом.

Утверждения, лексически содержащиеся в структурированном блоке.

Поток, создающий группу при входе в параллельную область.

Инструкции, которые связаны с параллельной конструкцией OpenMP и могут выполняться многими потоками.

Закрытая переменная присваивает имя блоку памяти, уникальному для потока, создающего ссылку. Существует несколько способов указать, что переменная является закрытой: определение в параллельной области, директива threadprivate, предложение private , firstprivate , lastprivate или сокращение или использование переменной в качестве управляющей переменной цикла for в цикле for немедленно. после директивы for или параллельной директиве for.

Динамический экстент.

Инструкции выполняются только главным потоком за пределами динамического экстента любой параллельной области.

Чтобы выполнить параллельную конструкцию с помощью:

группа потоков, состоящая только из одного потока (который является главным потоком для этой параллельной конструкции),

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

не влияет на значение, возвращаемое omp_in_parallel() (кроме эффектов любых вложенных параллельных конструкций).

Общая переменная называет один блок хранилища. Все потоки в команде, которые обращаются к этой переменной, также получают доступ к этому единому блоку хранилища.

Структурированный блок — это оператор (одиночный или составной), имеющий один вход и один выход. Если есть переход в оператор или из него, этот оператор является структурированным блоком. (Это правило включает вызов longjmp (3C) или использование throw , хотя вызов exit разрешен.) Если его выполнение всегда начинается с открытия < и всегда заканчивается при закрытии >, составной оператор представляет собой структурированный блок. . Оператор выражения, оператор выбора, оператор итерации или блок try являются структурированным блоком, если соответствующий составной оператор, полученный путем включения его в < и >, был бы структурированным блоком. Оператор перехода, оператор с меткой или оператор объявления не являются структурированным блоком.

Один или несколько потоков, взаимодействующих при выполнении конструкции.

Исполняющий объект, имеющий последовательный поток управления, набор частных переменных и доступ к общим переменным.

Идентификатор, необязательно дополненный именами пространств имен, который называет объект.

1.3 Модель исполнения

OpenMP использует модель параллельного выполнения fork-join. Хотя эта модель fork-join может быть полезна для решения различных проблем, она адаптирована для приложений на основе больших массивов. OpenMP предназначен для поддержки программ, которые правильно выполняются как в качестве параллельных программ (множество потоков выполнения и полная библиотека поддержки OpenMP). Это также для программ, которые выполняются правильно как последовательные программы (директивы игнорируются и простая библиотека заглушек OpenMP). Однако возможно и разрешено разработать программу, которая ведет себя некорректно при последовательном выполнении. Кроме того, различные степени параллелизма могут привести к различным числовым результатам из-за изменений в ассоциации числовых операций. Например, последовательное сокращение может иметь другой образец ассоциаций добавления, чем параллельное сокращение. Эти различные ассоциации могут изменить результаты сложения с плавающей запятой.

Программа, написанная с помощью OpenMP C/C++ API, начинает выполнение как один поток выполнения, который называется главным потоком. Главный поток выполняется в последовательной области до тех пор, пока не встретится первая параллельная конструкция. В API OpenMP C/C++ директива parallel представляет собой параллельную конструкцию. Когда встречается параллельная конструкция, главный поток создает группу потоков, и главный становится главным в группе.Каждый поток в команде выполняет операторы в динамическом экстенте параллельной области, за исключением конструкций разделения работы. Все потоки в команде должны сталкиваться с конструкциями разделения работы в одном и том же порядке, и один или несколько потоков выполняют операторы в связанном структурированном блоке. Барьер, подразумеваемый в конце конструкции разделения работы без предложения nowait, выполняется всеми потоками в группе.

Если поток изменяет общий объект, это влияет не только на его собственную среду выполнения, но и на другие потоки в программе. Модификация гарантированно будет завершена, с точки зрения другого потока, в следующей точке последовательности (как определено в базовом языке), только если объект объявлен изменчивым. В противном случае модификация гарантированно будет завершена после первого модифицирующего потока. Затем другие потоки (или одновременно) видят директиву flush, указывающую объект (явно или неявно). Когда директивы flush, подразумеваемые другими директивами OpenMP, не гарантируют правильного порядка побочных эффектов, программист должен предоставить дополнительные явные директивы flush.

По завершении параллельной конструкции потоки в команде синхронизируются на неявном барьере, и только главный поток продолжает выполнение. В одной программе может быть указано любое количество параллельных конструкций. В результате программа может многократно разветвляться и объединяться во время выполнения.

API OpenMP C/C++ позволяет программистам использовать директивы в функциях, вызываемых из параллельных конструкций. Директивы, которые не появляются в лексическом объеме параллельной конструкции, но могут находиться в динамическом объеме, называются несостоявшимися директивами. С помощью потерянных директив программисты могут выполнять основные части своей программы параллельно, внося лишь минимальные изменения в последовательную программу. С помощью этой функции вы можете кодировать параллельные конструкции на верхних уровнях дерева вызовов программы и использовать директивы для управления выполнением в любой из вызываемых функций.

Несинхронизированные вызовы функций вывода C и C++, которые записывают в один и тот же файл, могут привести к выводу, в котором данные, записанные разными потоками, появляются в недетерминированном порядке. Точно так же несинхронизированные вызовы функций ввода, которые считывают данные из одного и того же файла, могут считывать данные в недетерминированном порядке. Несинхронизированное использование ввода-вывода, когда каждый поток обращается к другому файлу, приводит к тем же результатам, что и последовательное выполнение функций ввода-вывода.

1.4 Соответствие

Реализация OpenMP C/C++ API является совместимой с 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. Эта спецификация OpenMP API ссылается на ISO/IEC 9899:1999 как C99.

ISO/IEC 9899:1990, Информационные технологии. Языки программирования. C. Эта спецификация OpenMP API ссылается на ISO/IEC 9899:1990 как C90.

ISO/IEC 14882:1998, Информационные технологии. Языки программирования. C++. Эта спецификация API OpenMP ссылается на ISO/IEC 14882:1998 как на C++.

Там, где в этой спецификации API OpenMP упоминается C, делается ссылка на базовый язык, поддерживаемый реализацией.

Читайте также: