Похожие презентации:
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
1if(scalar_expression)
Условное выполнение параллельной области.
Создание параллельной области осуществляется
только при истинности указанного условия
scalar_expression. Например:
#pragma omp parallel if( size >= 100000)
{
…
}
shared(список переменных)
Явно задаёт список ранее объявленных в тексте
программы переменных, общих для всех потоков.
#pragma omp parallel shared( sum, avg )
10. Опции директивы parallel
2private(список переменных)
По умолчанию переменные, видимые в области,
объемлющей блок параллельного исполнения, являются
общими (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
3firstprivate( список переменных )
Опция firstprivate делает то же, что и опция
private, но дополнительно все копии переменных в
каждом потоке инициализируются текущим значением
исходной переменной в мастер-потоке в момент
создания параллельного региона.
default( shared | none )
Значение none означает, что всем переменным
в задаче класс должен быть назначен явно.
Значение shared означает, что все переменные,
имена которых отсутствуют в списках опций private и
firstprivate, являются общими.
Рекомендуется всегда использовать опцию
default( none ).
12. Опции директивы parallel
4reduction( оператор : список общих переменных )
для каждой общей переменной указанного списка
создаются локальные (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 будет иметь корректное
//значение суммы всех элементов массива
Программирование