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

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

#pragma omp parallel

{

#pragma omp for

for(int i = 1; i < size; ++i)

x[i] = (y[i-1] + y[i+1])/2;

}

Если бы этот код выполнялся на четырехпроцессорном компьютере, а у переменной size было бы значение 100, то выполнение итераций 1—25 могло бы быть поручено первому процессору, 26—50 — второму, 51—75 — третьему, а 76—99 — четвертому. Это характерно для политики планирования, называемой статической.

В конце параллельного региона выполняется барьерная синхронизация (barrier synchronization) - достигнув конца региона, все потоки блокируются до тех пор, пока последний поток не завершит свою работу.

Если из только что приведенного примера исключить директиву #pragma omp for, каждый поток выполнит полный цикл for, проделав много лишней работы:

#pragma omp parallel

{

for(int i = 1; i < size; ++i)

x[i] = (y[i-1] + y[i+1])/2;

}

Так как циклы являются самыми распространенными конструкциями, где выполнение кода можно распараллелить, OpenMP поддерживает сокращенный способ записи комбинации директив #pragma omp parallel и #pragma omp for:

#pragma omp parallel for

for(int i = 1; i < size; ++i)

x[i] = (y[i-1] + y[i+1])/2;

В качестве более сложного примера рассмотрим сложение одномерных массивов (vector-add program). Массивы A, B, C, переменная N – общие для всех нитей. Переменная I – приватная(private) для каждой нити. Распределение итераций происходит динамически блоками размером CHUNK. Не выполняется синхронизация нитей. Нити завершившие обработку продолжают работу.

C / C++ - Пример использования директивы for #include <omp.h> #define CHUNKSIZE 100 #define N 1000 main () { int i, chunk; float a[N], b[N], c[N]; /* Some initializations */ for (i=0; i < N; i++) a[i] = b[i] = i * 1.0; chunk = CHUNKSIZE; #pragma omp parallel shared(a,b,c,chunk) private(i) { #pragma omp for schedule(dynamic,chunk) nowait for (i=0; i < N; i++) c[i] = a[i] + b[i]; } /* end of parallel section */ }

Пример использования опции reduction.

  • Итерации параллельного цикла распределяются блоками по 10 элементов по нитям.
  • В заключении параллельного цикла все нити складывают значения переменной result изменяя ее значение в основной программе.
C / C++ - Опция reduction #include <omp.h> main () { int i, n, chunk; float a[100], b[100], result; /* Some initializations */ n = 100; chunk = 10; result = 0.0; for (i=0; i < n; i++) { a[i] = i * 1.0; b[i] = i * 2.0; } #pragma omp parallel for \ default(shared) private(i) \ schedule(static,chunk) \ reduction(+:result) for (i=0; i < n; i++) result = result + (a[i] * b[i]); printf("Final result= %f\n",result); }

Restrictions:

  • Variables in the list must be named scalar variables. They can not be array or structure type variables. They must also be declared SHARED in the enclosing context.
  • Reduction operations may not be associative for real numbers.
  • The REDUCTION clause is intended to be used on a region or work-sharing construct in which the reduction variable is used only in statements which have one of following forms:
C / C++
x = x op expr x = expr op x (except subtraction) x binop = expr x++ ++x x-- --x
x is a scalar variable in the list expr is a scalar expression that does not reference xop is not overloaded, and is one of +, *, -, /, &, ^, |, &&, || binop is not overloaded, and is one of +, *, -, /, &, ^, |

Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: