Модель выполнения OpenMP-программ
Простой пример OpenMP-программы:
Активизация OpenMP
Модель памяти OpenMP
Директивы OpenMP
Структурные блоки директив
Группы директив OpenMP
Параллельное выполнение фрагмента программы
Опции директивы parallel
Опции директивы parallel
Опции директивы parallel
Опции директивы parallel
Опции директивы parallel
Пример использования директивы parallel и ее опций
627.50K
Категория: ПрограммированиеПрограммирование

parProgr03

1. Модель выполнения OpenMP-программ

Модель выполнения OpenMPпрограмм
В момент запуска программы порождается единственный
мастер-поток, который и начинает выполнение программы с
первого оператора.
Мастер-поток может создать параллельную область,
выполняемую им и несколькими дополнительными потоками.
Только мастер-поток исполняет все последовательные
области программы, находящиеся между параллельными
областями.
Дополнительные потоки
Мастер-поток
F
o
r
J
o
i
F
o
r
k
n
k


J
o
i
n

Параллельные регионы (области)

2. Простой пример OpenMP-программы:

#include <stdio.h>
#include <omp.h>
main () {
#pragma omp parallel //пример OpenMP-директивы
{
int nthreads, threadId;
threadId = omp_get_thread_num(); //OpenMP функция
printf("Hello World from thread = %d\n", threadId);
if (threadId == 0)
{
nthreads = omp_get_num_threads();
printf("Number of threads = %d\n", nthreads);
}
Hello World from thread 0
} Возможный вид результата работы: Hello World from thread 2
Number of threads =3
}
Hello World from thread 1

3. Активизация OpenMP

Для того, чтобы директивы OpenMP
действительно повлияли нужным образом на
результат компиляции программы, необходимо:
1. Указать компилятору ключ
o /openmp для Microsoft Visual Studio (при
использовании IDE установить флажок
«Поддержка OpenMP» в свойствах проекта
«С/С++ / Язык»)
o –fopenmp для gcc *nix
2. Включить в программу заголовочный файл
omp.h:
#include <omp.h>
3. Не забывать слово omp в каждой прагме.

4. Модель памяти OpenMP

Вся память системы является разделяемой (shared),
в которой могут существовать частные участки
отдельных потоков. Все переменные, объявленные
вне фрагментов, выполняемых в качестве
параллельных регионов, по умолчанию являются
разделяемыми или общими.
Закрытыми или частными (private) переменными
потока по умолчанию являются переменные,
объявленные внутри структурного блока,
исполняемого в параллельной области (за
исключением тех, которые объявлены как static);
Для каждой параллельной области могут быть явно
указаны списки общих и закрытых переменных, при
этом могут быть указаны также способы установки
их начальных значений и обработки тех значений,
которые они получили к моменту завершения
параллельной области;

5. Директивы OpenMP

Директивы пишутся так:
#pragma omp <имя_директивы> <опции>
<структурный блок текста программы>
Каждая директива со всеми ее
опциями пишется строго в одной строке.
Правильно:
#pragma omp parallel private( value )
Неправильно:
#pragma omp
parallel private( value )

6. Структурные блоки директив

Структурный блок – это либо один оператор, либо
последовательность операторов, заключенная в
фигурные скобки. Структурный блок имеет ровно одну
точку входа и одну точку выхода.
Например, неправильно:
#pragma omp parallel
{
double sum = 0.0;
for( int ind = 0; ind < size; ind += 1 )
sum += arr[ ind ];
InnerLoop:
//вторая точка входа в блок
for( int ndx = size – 2; ndx >= 0; ndx -= 1 )
arr[ ndx ] = (arr[ ndx ] + arr[ ndx + 1 ]) / sum;
}
if( arr[0] > limit )
goto InnerLoop;

7. Группы директив OpenMP

Создания параллельных областей
и управления потоками
2. Распределения вычислительных
работ между потоками
3. Синхронизации потоков
1.

8. Параллельное выполнение фрагмента программы

Основная директива:
#pragma omp parallel <опции>
<Структурный блок>
Список опций:
if (scalar_expression)
private (list)
firstprivate (list)
shared (list)
default (shared | none)
reduction (operator: list)
copyin (list)
num_threads (integer_expression)

9. Опции директивы parallel

1
if(scalar_expression)
Условное выполнение параллельной области.
Создание параллельной области осуществляется
только при истинности указанного условия
scalar_expression. Например:
#pragma omp parallel if( size >= 100000)
{

}
shared(список переменных)
Явно задаёт список ранее объявленных в тексте
программы переменных, общих для всех потоков.
#pragma omp parallel shared( sum, avg )

10. Опции директивы parallel

2
private(список переменных)
По умолчанию переменные, видимые в области,
объемлющей блок параллельного исполнения, являются
общими (shared). Переменные, объявленные внутри такого
блока, по умолчанию считаются закрытыми (private). Опция
private явно задает список тех shared-переменных, которые
должны быть частными/закрытыми в каждом потоке. Эти
переменные «размножаются» по потокам в момент
создания параллельного региона, их начальные значения
не определены. Переменная, объявляемая как private, не
должна быть указателем (потому что потоки получат
разные указатели на одно и то же значение).
int var = omp_get_threads_num(), count = 0, value =1, *ptr;
#pragma omp parallel private( var, value)
{
int tmp = var + omp_get_thread_num(); //ошибка!
*ptr = tmp;
//ошибка и проблема
if( tmp <= value)
//еще две ошибки!
count += 1; //потенциальная проблема!

11. Опции директивы parallel

3
firstprivate( список переменных )
Опция firstprivate делает то же, что и опция
private, но дополнительно все копии переменных в
каждом потоке инициализируются текущим значением
исходной переменной в мастер-потоке в момент
создания параллельного региона.
default( shared | none )
Значение none означает, что всем переменным
в задаче класс должен быть назначен явно.
Значение shared означает, что все переменные,
имена которых отсутствуют в списках опций private и
firstprivate, являются общими.
Рекомендуется всегда использовать опцию
default( none ).

12. Опции директивы parallel

4
reduction( оператор : список общих переменных )
для каждой общей переменной указанного списка
создаются локальные (private) копии в каждом
потоке, которые инициализируются соответственно
типу оператора (для аддитивных операций – 0 или
его аналоги, для мультипликативных операций – 1);
• в момент завершения параллельной области над
локальными копиями переменных выполняется
заданный оператор:
для языка С/С++:
+ , * , - , & , | , ^ , && , ||
для языка Фортран: +, *, -, .and., .or., .eqv., .neqv.,
max, min, iand, ior, ieor
• порядок выполнения операторов (над потоками)
не определён, поэтому результаты вычислений
редукции могут различаться от запуска к запуску.

13. Опции директивы parallel

num_threads ( целочисленное выражение )
Явное задание количества потоков, которые
будут выполнять параллельную область;
при отсутствии этой опции по умолчанию
выбирается либо последнее значение,
установленное с помощью вызова функции
void omp_set_num_threads( int ), либо значение
переменной среды OMP_NUM_THREADS;
copyin( список переменных )
Задаёт список переменных, объявленных как
threadprivate, которые при входе в параллельную
область инициализируются значениями
соответствующих переменных, находящихся в
мастер-потоке;
5

14. Пример использования директивы parallel и ее опций

int size, index, count = COUNT;
double sum;
double *arrayOfValues = new double( count );

#pragma omp parallel private(index) reduction( + : sum)
{
index = omp_get_thread_num( );
size = omp_get_num_threads( );
while( index < count ){
sum += arrayOfValues[ index ];
index += size;
}
}
//при выходе из параллельного региона
//переменная sum будет иметь корректное
//значение суммы всех элементов массива
English     Русский Правила