3. Функции библиотеки времени выполнения
В этом разделе описываются функции библиотеки времени выполнения OpenMP C и C++. Заголовок <omp.h> объявляет два типа, несколько функций, которые можно использовать для управления и запроса параллельной среды выполнения, а также функции блокировки, которые можно использовать для синхронизации доступа к данным.
Тип omp_lock_t
является типом объекта, способным представлять, что блокировка доступна или что поток владеет блокировкой. Эти блокировки называются простыми блокировками.
Тип omp_nest_lock_t
является типом объекта, способным представлять либо доступную блокировку, либо удостоверение потока, которому принадлежит блокировка, и число вложений (описано ниже). Эти блокировки называются вложенными блокировками.
Функции библиотеки — это внешние функции с компоновкой "C".
Описания в этой главе разделены на следующие разделы:
3.1 Функции среды выполнения
Функции, описанные в этом разделе, влияют на потоки, процессоры и параллельную среду:
- omp_set_num_threads
- omp_get_num_threads
- omp_get_max_threads
- omp_get_thread_num
- omp_get_num_procs
- omp_in_parallel
- omp_set_dynamic
- omp_get_dynamic
- omp_set_nested
- omp_get_nested
Функция 3.1.1 omp_set_num_threads
Функция 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_set_dynamic
- функция omp_get_dynamic
- переменная среды OMP_NUM_THREADS
- предложение num_threads
Функция 3.1.2 omp_get_num_threads
Функция 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
:
threads-used-for-next-team<=
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.
Перекрестные ссылки
Функция 3.1.5 omp_get_num_procs
Функция omp_get_num_procs
возвращает количество процессоров, доступных программе во время вызова функции. Используется следующий формат:
#include <omp.h>
int omp_get_num_procs(void);
Функция 3.1.6 omp_in_parallel
Функция 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
всегда возвращает определяемый пользователем номер, если он задан или номер потока по умолчанию. В текущей реализации Майкрософт отключите динамический поток, omp_set_dynamic(0)
чтобы существующий набор потоков можно повторно использовать для следующего параллельного региона. omp_set_dynamic(1)
включает динамическую потоковую обработку, отменив существующий набор потоков и создав новый набор для предстоящего параллельного региона. Число потоков в новом наборе совпадает со старым набором и основано на возвращаемом значении omp_get_num_threads
. Поэтому для оптимальной производительности используйте omp_set_dynamic(0)
повторное использование существующих потоков.
Перекрестные ссылки
Функция 3.1.8 omp_get_dynamic
Функция omp_get_dynamic
возвращает ненулевое значение, если включена динамическая корректировка потоков и возвращает значение 0 в противном случае. Используется следующий формат:
#include <omp.h>
int omp_get_dynamic(void);
Если реализация не реализует динамическую корректировку количества потоков, эта функция всегда возвращает значение 0. Дополнительные сведения см. в 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
Эти функции предоставляют единственный способ инициализации блокировки. Каждая функция инициализирует блокировку, связанную с блокировкой параметра для использования в предстоящих вызовах. Используется следующий формат:
#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
Эти функции позволяют неинициализировать блокировку переменной блокировки . Используется следующий формат:
#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
должен указывать на инициализированную переменную блокировки. Число вложенных объектов увеличивается, и поток предоставляется или сохраняется владение блокировкой.
Функции 3.2.4 omp_unset_lock и omp_unset_nest_lock
Эти функции предоставляют средства освобождения владения блокировкой. Используется следующий формат:
#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 возвращает секунды между последовательными тиками часов.
Функция 3.3.1 omp_get_wtime
Функция 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);