openmpНачало работы с openmp


замечания

OpenMP (Open MultiProcessing) - это модель параллельного программирования, основанная на директивах компилятора, которая позволяет разработчикам приложений постепенно добавлять параллелизм к их кодам приложений.

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

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

Версии

Версия язык Дата выхода
4.5 C / C ++ / Fortran 2015-11-01
4,0 C / C ++ / Fortran 2013-07-01
3,1 C / C ++ / Fortran 2011-07-01
3.0 C / C ++ / Fortran 2008-05-01
2.5 C / C ++ / Fortran 2005-05-01
2.0c C / C ++ 2002-03-01
2.0f Фортран 2000-11-01
1.0c C / C ++ 1998-10-01
1.0f Фортран 1997-10-01

компиляция

Существует много компиляторов, которые поддерживают разные версии спецификации OpenMP. OpenMP поддерживает список здесь с компилятором, который поддерживает его и поддерживаемую версию. В общем случае для компиляции (и связывания) приложения с поддержкой OpenMP вам нужно только добавить флаг компиляции, и если вы используете OpenMP API, вам необходимо включить заголовок OpenMP (omp.h). Хотя заголовочный файл имеет фиксированное имя, флаг компиляции зависит от компилятора. Ниже приведен неисчерпывающий список компиляторов и флаг, который разрешает OpenMP.

  • GCC (включая gcc, g ++ и gfortran): -fopenmp
  • LLVM: -fopenmp
  • Intel compiler-suite (включая icc, icpc и ifort): -qopenmp-fopenmp для совместимости с GCC / LLVM)
  • Набор компиляторов IBM XL (включая xlc, xlC и xlf): -xlsmp=omp
  • Компилятор PGI-пакета (включая pgcc pgc ++ pgfortran): '-mp'

Параллельный мир привет с использованием OpenMP

#include <omp.h>
#include <stdio.h>

int main (int argc, char *argv[])
{
   #pragma omp parallel
   {
     printf ("Hello world! I'm thread %d out of %d threads.\n",
             omp_get_thread_num(), omp_get_num_threads());
   }
   return 0;
}
 

Этот код просто создает группу потоков (в соответствии с переменной окружения OMP_NUM_THREADS - и если не определен, будет создаваться по одному для каждого логического ядра в системе), и каждый поток идентифицирует себя, помимо печати типичного приветственного сообщения Hello.

Пример сокращения

#include <omp.h>
void main ()
{     
    int i;       
    double ZZ, func(), res=0.0;

    #pragma omp parallel for reduction(+:res) private(ZZ) 
    for (i=0; i< 1000; i++){
        ZZ = func(I);
        res = res + ZZ; 
    }
}
 

В последней строке: Фактически добавляется в частную копию, затем объединяется после цикла. Компилятор заботится о деталях.

Конструкция совместного использования - пример цикла for

double  res[MAX];  int i;
#pragma omp parallel 
{    
    #pragma omp for
    for (i=0;i< MAX; i++) {
        res[i] = huge();
    } 
}    
 

Цикл for будет выполняться параллельно. Огромный () - это некоторый метод, который может занять слишком много времени, чтобы получить выполнение. OpenMP поддерживает ярлык для написания вышеуказанного кода как:

double  res[MAX];  int i;
#pragma omp parallel for
for (i=0;i< MAX; i++) {
    res[i] = huge();
} 
 

Мы также можем иметь предложение расписания, которое влияет на то, как итерации цикла сопоставляются потокам. Например:

#pragma omp parallel
#pragma omp for schedule(static)
for(i=0;I<N;i++) {
    a[i] = a[i] + b[i];
}
 

Различные стили планирования:

расписание (статический [, кусок])
Выделите блоки итераций размера «кусок» для каждой нити.
Если не указано: распределите как можно равномернее доступные потоки

График (динамический [, фрагмент])
Каждый поток захватывает итерации «chunk» с очереди, пока не будут обработаны все итерации.

График (руководствуясь [, фрагмент])
Темы динамически захватывают блоки итераций. Размер блока начинается с большого размера и уменьшается до размера «кусок» по мере того, как вычисление продолжается.

график (выполнения)
Расписание и размер блока, взятые из переменной среды OMP_SCHEDULE.