Россия, г. Саранск |
Параллельное программирование с использованием OpenMP
7.7.5. Управление количеством потоков
По умолчанию количество создаваемых потоков определяется реализацией и обычно совпадает с числом имеющихся вычислительных элементов в системе (процессоров и/или ядер )4Определение количества имеющихся вычислительных элементов осуществляется операционной системой. При этом следует понимать, что при аппаратной поддержке процессором технологии многопоточности (hyperthreading, HT) ОС будет воспринимать каждый процессор как несколько логических вычислительных элементов (по числу аппаратно поддерживаемых потоков).. При необходимости количество создаваемых потоков может быть изменено - для этой цели в OpenMP предусмотрено несколько способов действий.
Прежде всего, количество создаваемых потоков может быть задано при помощи параметра num_threads директивы parallel.
Количество необходимых потоков может быть также задано при помощи функции omp_set_num_threads библиотеки OpenMP.
Формат функции omp_set_num_threads имеет вид:
void omp_set_num_threads (int num_threads);
Вызов функции omp_set_num_threads должен осуществляться из последовательной части программы.
Для задания необходимого количества потоков можно воспользоваться и переменной окружения OMP_NUM_THREADS. При использовании нескольких способов задания наибольший приоритет имеет параметр num_threads директивы parallel, затем функция библиотеки, затем переменная окружения.
Изменение количества создаваемых потоков может быть полезно и для целей отладки разрабатываемой параллельной программы для проверки ее работоспособности при разном количестве потоков.
Приведем здесь также дополнительные функции библиотеки OpenMP, которые могут быть использованы при работе с потоками:
- Получение максимально-возможного количества потоков:
int omp_get_max_threads(void)
- Получение фактического количества потоков в параллельной области программы:
int omp_get_num_threads(void)
- Получение номера потока:
int omp_get_thread_num(void)
- Получение числа вычислительных элементов (процессоров или ядер), доступных приложению:
int omp_get_num_procs(void)
7.7.6. Задание динамического режима при создании потоков
Количество создаваемых потоков в параллельных фрагментах программы по умолчанию является фиксированным (см. также предыдущий пункт), однако стандартом предусматривается возможность динамического режима, когда количество потоков может определяться реализацией для оптимизации функционирования вычислительной системы. Разрешение динамического режима и его отключение осуществляется при помощи функции omp_set_dynamic библиотеки OpenMP.
Формат функции omp_set_ dynamic имеет вид:
void omp_set_dynamic (int dynamic);
Вызов функции omp_set_dynamic должен осуществляться из последовательной части программы. Функция разрешает ( dynamic=true )илиотключает ( dynamic=false )динамический режим создания потоков.
Для управления динамическим режимом создания потоков можно воспользоваться и переменной окружения OMP_DYNAMIC. При использовании нескольких способов задания наибольший приоритет имеет функция библиотеки, затем переменная окружения.
Для получения состояния динамического режима можно воспользоваться функций omp_get_dynamic библиотеки OpenMP:
int omp_get_dynamic (void);
7.7.7. Управление вложенностью параллельных фрагментов
Параллельные фрагменты программы могут быть вложенными - такая возможность определяется реализацией OpenMP. По умолчанию для выполнения вложенных параллельных фрагментов создается столько же потоков, как и для параллельных фрагментов верхнего уровня..
Управление режимом выполнения вложенных фрагментов осуществляется при помощи функции omp_set_nested библиотеки OpenMP.
Формат функции omp_set_nested имеет вид:
void omp_set_nested (int nested);
Вызов функции omp_set_nested должен осуществляться из последовательной части программы. Функция разрешает (nested=true)илиотключает (nested=false)режим поддержки вложенных параллельных фрагментов.
Для управления режимом поддержки вложенных параллельных фрагментов можно воспользоваться и переменной окружения OMP_NESTED. При использовании нескольких способов задания наибольший приоритет имеет функция библиотеки, затем переменная окружения.
Для получения состояния режима поддержки вложенных параллельных фрагментов можно воспользоваться функций omp_get_nested библиотеки OpenMP:
int omp_get_nested (void);
7.8. Дополнительные сведения
Итак, возможности технологии OpenMP рассмотрены практически полностью. В данном подразделе дополнительно рассматриваются правила разработки параллельных программ с использованием OpenMP на алгоритмическом языке Fortran, описывается возможность компиляции программы как обычного последовательного программного кода и приводится краткий перечень компиляторов, обеспечивающих поддержку OpenMP
7.8.1. Разработка параллельных программ с использованием OpenMP на алгоритмическом языке Fortran
Между разработкой параллельных программ с использованием OpenMP на алгоритмическом языке С и алгоритмических языках семейства Fortran (Fortran 77, Fortran 90 и Fortran 95) существует не так много различий.
Прежде всего формат директив OpenMP на алгоритмическом языке Fortran имеет следующий вид:
<маркер> <имя_директивы> [<параметр>…]
Вид маркера зависит от формата записи программы:
- При фиксированном формате записи маркер имеет вид
!$omp или c$omp или *$omp
Маркер должен начинаться с позиции 1 строки. При этом сама директива может быть записана в несколько строк; первая строка директивы должна содержать в позиции 6 или пробел или 0; строки продолжения директивы в позиции 6 должны быть отмечены любым произвольным символом, отличающимся от пробела и 0.
- При свободном формате записи маркер должен иметь вид !$omp. Маркер может быть записан, начиная с произвольной позиции строки, при этом маркеру должны предшествовать только пробелы или знаки табуляции. При размещении директивы на нескольких строках первая строка должна заканчиваться символом &, строки продолжения могут начинаться с этого знака, но приводить его в строках продолжения не обязательно.
В качестве основных отличий параллельных программ с использованием OpenMP на алгоритмическом языке Fortran отметим следующее:
- Практически все директивы сопровождаются соответствующей директивой завершения; к директивам завершения относятся:
end critical end do end master end ordered end parallel end sections end single end workshare
- В стандарте OpenMP для алгоритмического языка Fortran предусматривается дополнительная директива workshare, которая является близкой по своему назначению директиве sections.
- Часть подпрограмм библиотеки OpenMP являются процедурами и, тем самым, должны вызываться при помощи оператора вызова процедур CALL.
В качестве принятых соглашений при разработке программ на языке Fortran рекомендуется записывать имена подпрограмм с использованием прописных символов.
В качестве примера приведем вариант программы из примера 7.6 на алгоритмическом языке Fortran.
PROGRAM Example INCLUDE "omp_lib.h" INTEGER NMAX 1000 INTEGER LIMIT 100 INTEGER I, J, SUM REAL A(NMAX,NMAX) <инициализация данных> !$OMP PARALLEL DO SHARED(A) PRIVATE(I,J,SUM) IF (NMAX>LIMIT) DO I = 1, NMAX SUM = 0 DO J = 1, NMAX SUM = SUM + A(I,J) ENDDO PRINT * "Сумма элементов строки ", I, "равна ", SUM ENDDO !$OMP END PARALLEL DO ! Завершение параллельного фрагмента STOP END7.13. Пример параллельной программы с использованием OpenMP на алгоритмическом языке Fortran
7.8.2. Сохранение возможности последовательного выполнения программы
При разработке параллельной программы с использованием OpenMP в общем случае целесообразно сохранить возможность компиляции программы как обычного последовательного кода (обычно говорят о единственности программного кода для последовательного и параллельного вариантов программ). При соблюдении такого подхода значительно снижаются затраты на сопровождение и развитие программ - так, например, при необходимости изменений в общей части алгоритмов последовательных и параллельных вычислений не требуется проводить корректировку программного кода в разных вариантах программ. Указанный подход полезен и при использовании компиляторов, которые все еще не поддерживают технологию OpenMP. И, наконец, последовательный вариант программы часто необходим для проведения вычислительных экспериментов при определении получаемого ускорения параллельных вычислений.
Поддержка единственности программного кода относится к числу важных положительных качеств технологии OpenMP - формат директив был специально подобран таким образом, чтобы "обычные" компиляторы без поддержки OpenMP воспринимали директивы как комментарии.
Однако проблемы поддержки единственности программного кода возникают при использовании в параллельной программе функций и переменных окружения OpenMP в явном виде. Данные проблемы могут быть решены с помощью директив условной компиляции средств препроцессирования. Стандартом OpenMP предусматривается, что компиляторы с поддержкой технологии OpenMP должны определять макропеременную _OPENMP, значением которой является дата поддерживаемого стандарта в формате ГГГГММ (год, месяц). Как результат, для обеспечения единственности программного кода последовательного и параллельного вариантов программ, все OpenMP-зависимые расширения параллельного варианта программы следует окружать директивами условной компиляции в виде:
#ifdef _OPENMP <OpenMP-зависимый программный код> #endif
Последовательный вариант программы может порождаться и компиляторами с поддержкой OpenMP - для обеспечения такой возможности в составе OpenMP имеются функции-заглушки для всех функций библиотеки OpenMP. Указание подобного режима компиляции осуществляется при помощи соответствующих параметров компилятора.
7.8.3. Краткий перечень компиляторов с поддержкой OpenMP
Среди компиляторов с поддержкой OpenMP прежде всего следует отметить компиляторы компании Intel для алгоритмических языков Fortran и C/C++ для операционных систем семейств Unix и Windows. В следующей таблице приведены параметры этих компиляторов для управления возможностями OpenMP.
Следует также помнить, что при сборке программы следует использовать библиотеки, обеспечивающие поддержки многопоточности.
Среди других компиляторов можно отметить:
- Fujitsu/Lahey Fortran, C and C++,
- HP Fortran, C and C++,
- IBM Fortran and C,
- Silicon Graphics. Fortran 77/90 (IRIX), C/C++,
- Portland Group (PGI). Fortran и C/C++ для Windows NT, Linux, Solaris (x86).
Полный перечень компиляторов, поддерживающих OpenMP представлен на портале www.openmp.org.