3. Функции библиотеки исполняемой среды

В этом разделе описываются функции библиотеки времени выполнения OpenMP C и C++. Заголовок <omp.h> объявляет два типа, несколько функций, которые можно использовать для управления и запроса параллельной среды выполнения, а также функции блокировки, которые можно использовать для синхронизации доступа к данным.

Тип omp_lock_t является типом объекта, способным представлять, что блокировка доступна или что поток владеет блокировкой. Эти блокировки называются простыми блокировками.

Тип omp_nest_lock_t является типом объекта, способным представлять как наличие доступной блокировки, так и идентификатор потока, который владеет блокировкой, и число вложений (описано ниже). Эти блокировки называются вложенными блокировками.

Функции библиотеки — это внешние функции с компоновкой "C".

Описания в этой главе разделены на следующие разделы:

3.1 Функции среды выполнения

Функции, описанные в этом разделе, влияют на потоки, процессоры и параллельную среду:

Функция omp_set_num_threads 3.1.1

Функция omp_set_num_threads задает количество потоков по умолчанию для последующего использования в параллельных регионах, которые не указывают директиву num_threads. Используется следующий формат:

#include <omp.h>
void omp_set_num_threads(int num_threads);

Значение параметра num_threads должно быть положительным целым числом. Его влияние зависит от того, включена ли динамическая корректировка количества потоков. Полный набор правил взаимодействия между функцией omp_set_num_threads и динамической корректировкой потоков см. в разделе 2.3.

Эта функция имеет эффекты, описанные выше при вызове из части программы, где omp_in_parallel функция возвращает ноль. Если он вызывается из части программы, в которой omp_in_parallel функция возвращает ненулевое значение, поведение этой функции не определено.

Этот вызов имеет приоритет над переменной OMP_NUM_THREADS среды. Значение по умолчанию для количества потоков, которое может быть установлено путем вызова omp_set_num_threads или установки переменной среды OMP_NUM_THREADS, можно явно переопределить для одной директивы parallel, указав условие num_threads.

Дополнительные сведения см. в omp_set_dynamic.

Перекрестные ссылки

Функция omp_get_num_threads (раздел 3.1.2)

Функция omp_get_num_threads возвращает количество потоков в команде, выполняющей параллельный регион, из которого он вызывается. Используется следующий формат:

#include <omp.h>
int omp_get_num_threads(void);

Предложение num_threads , omp_set_num_threads функция и OMP_NUM_THREADS переменная среды управляют количеством потоков в команде.

Если число потоков не было явно задано пользователем, значение по умолчанию определяется реализацией. Эта функция привязывается к ближайшей включающей директиве parallel. Если вызывается из последовательной части программы или из вложенного параллельного региона, сериализованного, эта функция возвращает значение 1.

Дополнительные сведения см. в omp_set_dynamic.

Перекрестные ссылки

Функция 3.1.3 omp_get_max_threads

Функция omp_get_max_threads возвращает целое число, которое гарантированно будет не меньше количества потоков, используемых для формирования команды, если в данном месте кода встретится параллельный регион без предложения num_threads. Используется следующий формат:

#include <omp.h>
int omp_get_max_threads(void);

Ниже приведено выражение нижней границы для значения omp_get_max_threads:

потоки, используемые для следующей команды<= omp_get_max_threads

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

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

Перекрестные ссылки

Функция 3.1.4 omp_get_thread_num

Функция omp_get_thread_num возвращает номер потока в команде, к которой принадлежит поток, выполняющий эту функцию. Число потока находится в диапазоне от 0 до omp_get_num_threads()–1 (включительно). Главный поток команды — поток 0.

Используется следующий формат:

#include <omp.h>
int omp_get_thread_num(void);

При вызове из последовательного региона omp_get_thread_num возвращается значение 0. При вызове из вложенного параллельного региона, сериализованного, эта функция возвращает значение 0.

Перекрестные ссылки

Функция omp_get_num_procs, раздел 3.1.5

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

#include <omp.h>
int omp_get_num_procs(void);

Функция omp_in_parallel 3.1.6

Функция omp_in_parallel возвращает ненулевое значение, если оно вызывается в динамической степени параллельного региона, выполняемого параллельно; в противном случае возвращается значение 0. Используется следующий формат:

#include <omp.h>
int omp_in_parallel(void);

Эта функция возвращает ненулевое значение при вызове из региона, выполняющегося параллельно, включая вложенные регионы, сериализованные.

Раздел 3.1.7: функция omp_set_dynamic

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

#include <omp.h>
void omp_set_dynamic(int dynamic_threads);

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

Если dynamic_threads оценивается как 0, то динамическая корректировка отключена.

Эта функция имеет эффекты, описанные выше при вызове из части программы, где omp_in_parallel функция возвращает ноль. Если он вызывается из части программы, в которой omp_in_parallel функция возвращает ненулевое значение, поведение этой функции не определено.

Вызов omp_set_dynamic имеет приоритет над переменной OMP_DYNAMIC среды.

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

Только для систем Майкрософт

Текущая поддержка omp_get_dynamic и omp_set_dynamic выглядит следующим образом:

Входной параметр omp_set_dynamic не влияет на политику потоков и не изменяет количество потоков. omp_get_num_threads всегда возвращает определяемый пользователем номер, если он задан или номер потока по умолчанию. В текущей реализации Microsoft отключается динамическая многопоточность, что позволяет существующему набору потоков быть повторно использованным для следующего параллельного региона. omp_set_dynamic(1) включает динамическую потоковую обработку, отменив существующий набор потоков и создав новый набор для предстоящего параллельного региона. Число потоков в новом наборе совпадает со старым набором и основано на возвращаемом значении omp_get_num_threads. Поэтому для оптимальной производительности используйте omp_set_dynamic(0) для повторного использования существующих потоков.

Перекрестные ссылки

Функция omp_get_dynamic 3.1.8

Функция omp_get_dynamic возвращает ненулевое значение, если включена динамическая корректировка потоков и возвращает значение 0 в противном случае. Используется следующий формат:

#include <omp.h>
int omp_get_dynamic(void);

Если реализация не реализует динамическую корректировку количества потоков, эта функция всегда возвращает значение 0. Дополнительные сведения см. в omp_set_dynamic.

Перекрестные ссылки

  • Описание динамической настройки потоков см. в разделе omp_set_dynamic.

Функция 3.1.9 omp_set_nested

Функция omp_set_nested включает или отключает вложенный параллелизм. Используется следующий формат:

#include <omp.h>
void omp_set_nested(int nested);

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

Эта функция имеет эффекты, описанные выше при вызове из части программы, где omp_in_parallel функция возвращает ноль. Если он вызывается из части программы, в которой omp_in_parallel функция возвращает ненулевое значение, поведение этой функции не определено.

Этот вызов имеет приоритет над переменной OMP_NESTED среды.

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

Перекрестные ссылки

Функция 3.1.10 omp_get_nested

Функция omp_get_nested возвращает ненулевое значение, если вложенный параллелизм включен и 0, если он отключен. Дополнительные сведения о вложенном параллелизме см. в omp_set_nested. Используется следующий формат:

#include <omp.h>
int omp_get_nested(void);

Если реализация не реализует вложенный параллелизм, эта функция всегда возвращает значение 0.

Функции блокировки 3.2

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

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

  • Функция omp_init_lock инициализирует простую блокировку.
  • Функция omp_destroy_lock удаляет простую блокировку.
  • Функция omp_set_lock ожидает, пока не будет доступна простая блокировка.
  • Функция omp_unset_lock освобождает простую блокировку.
  • Функция omp_test_lock проверяет простую блокировку.

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

  • Функция omp_init_nest_lock инициализирует вложенную блокировку.
  • Функция omp_destroy_nest_lock удаляет условно вложенную блокировку.
  • Функция omp_set_nest_lock ожидает, пока не будет доступна вложенная блокировка.
  • Функция omp_unset_nest_lock освобождает вложенную блокировку.
  • Функция omp_test_nest_lock тестирует вложенную блокировку.

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

Функции 3.2.1 omp_init_lock и omp_init_nest_lock

Эти функции предоставляют единственный способ инициализации блокировки. Каждая функция инициализирует блокировку, связанную с параметром lock, для использования в будущих вызовах. Используется следующий формат:

#include <omp.h>
void omp_init_lock(omp_lock_t *lock);
void omp_init_nest_lock(omp_nest_lock_t *lock);

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

Функции 3.2.2 omp_destroy_lock и omp_destroy_nest_lock

Эти функции проверяют, что переменная блокировки lock неинициализирована. Используется следующий формат:

#include <omp.h>
void omp_destroy_lock(omp_lock_t *lock);
void omp_destroy_nest_lock(omp_nest_lock_t *lock);

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

Функции 3.2.3 omp_set_lock и omp_set_nest_lock

Каждая из этих функций блокирует поток, выполняющий функцию, пока указанная блокировка не будет доступна, а затем задает блокировку. Простая блокировка доступна, если она разблокирована. Вложенная блокировка доступна, если она не заблокирована или если она уже принадлежит потоку, который выполняет функцию. Используется следующий формат:

#include <omp.h>
void omp_set_lock(omp_lock_t *lock);
void omp_set_nest_lock(omp_nest_lock_t *lock);

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

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

Функции omp_unset_lock и omp_unset_nest_lock в разделе 3.2.4

Эти функции предоставляют средства освобождения владения блокировкой. Используется следующий формат:

#include <omp.h>
void omp_unset_lock(omp_lock_t *lock);
void omp_unset_nest_lock(omp_nest_lock_t *lock);

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

Для простой блокировки функция omp_unset_lock освобождает поток, выполняющего функцию, от владения блокировкой.

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

Функции 3.2.5 omp_test_lock и omp_test_nest_lock

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

#include <omp.h>
int omp_test_lock(omp_lock_t *lock);
int omp_test_nest_lock(omp_nest_lock_t *lock);

Аргумент должен указывать на инициализированную переменную блокировки. Эти функции пытаются задать блокировку таким же образом, как omp_set_lock и omp_set_nest_lock, за исключением того, что они не блокируют выполнение потока.

Для простой блокировки функция возвращает ненулевое значение, omp_test_lock если блокировка успешно задана; в противном случае возвращается ноль.

Для гнездовой блокировки функция omp_test_nest_lock возвращает новый уровень вложенности, если блокировка успешно установлена; в противном случае возвращается ноль.

3.3 Подпрограммы времени

Функции, описанные в этом разделе, поддерживают переносимый часовой таймер:

  • Функция omp_get_wtime возвращает истекшее время часов.
  • Функция omp_get_wtick возвращает секунды между последовательными тиками часов.

Функция omp_get_wtime 3.3.1

Функция omp_get_wtime возвращает значение типа двойной точности с плавающей запятой, равное прошедшему времени по настенным часам, в секундах, начиная с некоторого времени в прошлом. Фактическое "время в прошлом" является произвольным, но оно гарантированно не изменится во время выполнения программы приложения. Используется следующий формат:

#include <omp.h>
double omp_get_wtime(void);

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

double start;
double end;
start = omp_get_wtime();
... work to be timed ...
end = omp_get_wtime();
printf_s("Work took %f sec. time.\n", end-start);

Возвращаемые времена — "время выполнения по потокам", что означает, что они не должны быть глобально синхронизированы во всех потоках, задействованных в приложении.

Функция 3.3.2 omp_get_wtick

Функция omp_get_wtick возвращает число с плавающей точкой двойной точности, которое определяет количество секунд между последовательными тактами часов. Используется следующий формат:

#include <omp.h>
double omp_get_wtick(void);