Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции_MPI_OpenMP.doc
Скачиваний:
4
Добавлен:
16.11.2019
Размер:
1.09 Mб
Скачать
  1. if(скалярное_выражение)

  2. private(список)

  3. firstprivate(список)

  4. Default(shared | none)

  5. shared(список)

  6. copyin(список)

  7. reduction(оператор: список)

1. Если значение выражения в if истинно, область выполняется параллельно, равно нулю (условие не выполняется), то область parallel выполняется последовательно.

2. private(список) - объявляет перечисленные в списке переменные локальными в каждой нити группы. При входе в параллельную область для каждой локальной переменной в каждой нити создается отдельный экземпляр переменной, доступный только этой нити, который не имеет никакой связи с оригинальной переменной вне параллельной области, т.е. при входе и выходе из параллельной области значение переменной не определено, поэтому при входе требуется инициализация. Изменение нитью значения своей локальной переменной, не влияет на изменение значения этой же локальной переменной в других нитях.

3. firstprivate(список) - объявляет перечисленные в списке переменные локальными в каждой нити группы. Локальные копии переменных при входе в параллельную область инициализируются значением оригинальной переменной, при выходе не определены.

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

Пример:

………….. // код программы

int i, j;

i =1; j =2;

#pragma omp parallel private(i) firstprivate(j)

{

i =3; // i - private переменная, значение при входе в параллельную область не

// определено, поэтому выполняется инициализация

j =i+j; // j - firstprivate переменная, значение при входе в параллельную область

// определено и равно 2

}

cout<<”i=”<<i<<” j=”<<j<<endl;

………….. // код программы

Переменные i и j при выходе из параллельной области сохранят свои оригинальные значения, т.е. значения до входа в параллельную область i=1, j=2.

Пример:

#pragma omp parallel

{

#pragma omp for lastprivate(i) //значение i не определено при входе,

for (i=0; i<10; i++) // поэтому выполняется инициализация

a[i] = b[i] + 1;

}

a[i-1]=b[i-1];

В значение i в конце параллельной области будет равно 10, как в случае последовательного выполнения цикла.

5. default(shared | none) позволяет установить область видимости переменных. По умолчанию устанавливается shared.

Использование default(none) требует, чтобы для каждой переменной в параллельной секции была явно задана область видимости. В директиве parallel может быть определен единственный оператор default.

Переменные могут быть исключены из умалчиваемого определения путем использования директив private, firstprivate, lastprivate, reduction и shared, например:

#pragma omp parallel for default(shared) firstprivate(i) private(x) private(r) lastprivate(i)

6. shared(список) - объявляет перечисленные в списке переменные общими для всех нитей группы. Т.е. каждая общая переменная существует в одном экземпляре для всей программы и доступна для каждой нити под одним и тем же именем.

Пример: Каждая нить в параллельной области принимает решение, основываясь на номере нити, какую часть массива x обрабатывать.

#pragma omp parallel shared(x, npoints) private(iam, np, ipoints)

{

iam = omp_get_thread_num();

np = omp_get_num_threads();

ipoints = npoints / np;

subdomain(x, iam, ipoints); //функция обработки массива x

}

7. copyin(список) - выполняет присвоение одного и того же значения переменной, определенной в threadprivate в каждую нить параллельной области. Т.е. для каждой переменной, указанной в операторе copyin, значение переменной из основной нити при воде в параллельную область копируется в приватные копии переменных каждой нити. Ограничения, накладываемые на использование клаузы copyin следующее - переменные, указанные в copyin, должны быть переменными threadprivate.

8. reduction(операция: список) - выполняет редукцию переменных, которые перечислены в списке, с оператором op. Список переменных перечисляется через запятую.

Допустимые операции: +, -, *, /, &, |, ||, &&

Ограничения, накладываемые на использование директивы reduction:

1. Тип переменных должен быть приемлемым для операции редукции, не разрешены типы указателя и ссылки.

2.Переменные, которые указаны в клаузе reduction, не должны быть константами.

3.Переменные, которые указаны в клаузе reduction, должны быть разделяемыми в общем контексте программы.

Пример: В данном примере каждая нить имеет свою копию переменной редукции: a и y. После окончания работы выполняется операция редуцирования (в данном случае сложение) всех локальных копий переменных.

#pragma omp parallel for reduction(+: a, y)

for (i=0; i<n; i++) {

a += b[i];

y = sum(y, c[i]);

}

Переменные в операторе reduction должны быть shared в параллельной секции.

.

Пример:

/*ОШИБКА – private переменная y не может быть определена в операторе reduction*/

……. // код программы

#pragma omp parallel for private(y) reduction(+: y)

for (i=0; i<n; i++)

y += b[i];

……. // код программы

Оператор reduction должен выполнить заданную в нем операцию (в данном примере сложение) над значениями указанных переменных (в данном примере y), но переменная y объявлена защищенной (private), а значения защищенных переменных на выходе из параллельного блока не определены. Поэтому, выполнить операцию сложения, заданную в reduction невозможно, а следовательно невозможно выполнить оператор reduction.

Пример:

/*ОШИБКА 2 – переменная x не может быть определена одновременно в операторах shared и reduction */

#pragma omp parallel for shared(x) reduction(+: x)

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

Программа вычисляет и записывает сумму значений элементов массива a в переменную x и сумму значений элементов массива b в переменную y

#include<stdio.h>

#include<omp.h>