- Главная
- Информатика
- parProgr04
Содержание
- 2. Директива section #pragma omp section Перед первым участком кода в блоке sections директива section не обязательна
- 3. Параллельные циклы. Директива for Синтаксис: #pragma omp for [ опция [ [,] опция]... ] Эта директива
- 4. Дополнительные требования к распараллеливаемому циклу Кроме того, должны выполняться следующие требования: Корректная программа не должна зависеть
- 5. Пример неверного использования директивы for #include #include #include #define ARRAYSIZE … int main( ) { //
- 6. Результаты работы неверной программы пузырьковой сортировки int arrayX[ ] = {3, 82, 17, 33, 82, 91,
- 7. Опции директивы for private( список переменных) firstprivate( список переменных ) lastprivate( список переменных ) reduction( оператор
- 8. Опция schedule schedule( type[ , chunk ] ) Задаёт способ распределения итераций цикла по потокам. type
- 9. Опция schedule schedule( type[, chunk] ) type = dynamic – динамическое распределение итераций с фиксированным размером
- 10. Опция schedule schedule( type[, chunk] ) type = guided – динамическое распределение итераций, при котором размер
- 11. Опция schedule schedule( type[, chunk] ) type = auto – способ распределения итераций (static, dynamic или
- 12. Опции директивы for ordered Эта опция, указывает компилятору, что в теле цикла могут встречаться директивы omp
- 13. Параллельная пузырьковая сортировка Алгоритм пузырьковой сортировки в прямом виде не может быть распараллелен, потому что на
- 14. Параллельная пузырьковая сортировка #define compExch( x, y ) if( x > y ){ tmp=x; x=y; y=tmp;}
- 15. Задачи (tasks) только начиная с версии 3.0 Синтаксис: #pragma omp task [опция [[,] опция]...] Начиная с
- 16. Пример использования директивы task struct node { struct node *left; struct node *right; dataType data; };
- 17. Директивы taskwait и taskyeld #pragma omp taskwait Поток, выполнивший эту директиву, приостанавливается до тех пор, пока
- 18. Группа директив синхронизации Синхронизация работы потоков в OpenMP может выполняться и явно и неявно. Неявная синхронизация
- 20. Скачать презентацию
Слайд 2Директива section
#pragma omp section
Перед первым участком кода в блоке sections директива
Директива section
#pragma omp section
Перед первым участком кода в блоке sections директива
Неизвестно, как будут распределены потоки между секциями (первая секция не обязательно будет выполняться потоком номер 0 или потоком номер 1, …).
Если количество потоков больше количества секций, то часть потоков (какая именно – заранее не определено) для выполнения данного блока секций не будет задействована.
Если наоборот, потоков меньше, чем секций, то некоторым (или всем) потокам достанется выполнение более, чем по одной секции. Пример низкоуровневого распараллеливания:
#pragma omp sections firstprivate( alfa, beta ) shared( n )
{
#pragma omp section
{
for (int i = 1; i < n; ++i) alfa[ i ] = alfa[ i-1 ] + 1;
}
#pragma omp section
{
for (int i = 1; i < n; ++i) beta[ i ] = beta[ i-1 ] - 1;
}
…
Слайд 3Параллельные циклы.
Директива for
Синтаксис:
#pragma omp for [ опция [ [,] опция]... ]
<структурный блок>
Эта
Параллельные циклы.
Директива for
Синтаксис:
#pragma omp for [ опция [ [,] опция]... ]
<структурный блок>
Эта
Главное ограничение состоит в том, что заголовок цикла должен выглядеть так:
for( [ целочисленный тип ] i = инвариант цикла;
i { <,>,=,<=,>= } инвариант цикла;
i { +,- }= инвариант цикла )
Если директива параллельного выполнения стоит перед гнездом циклов, завершающихся одним оператором, то директива воздействует только на самый внешний цикл.
Слайд 4Дополнительные требования к распараллеливаемому циклу
Кроме того, должны выполняться следующие требования:
Корректная программа
Дополнительные требования к распараллеливаемому циклу
Кроме того, должны выполняться следующие требования:
Корректная программа
Нельзя использовать побочный выход из параллельного цикла (операторы goto, break, continue).
Размер блока итераций, указанный в опции schedule директивы for (если эта опция указана), не должен изменяться в рамках цикла.
Итеративная переменная распределяемого цикла по смыслу должна быть локальной, поэтому в том случае, если она специфицирована в качестве общей переменной, то неявно делается локальной при входе в цикл. После завершения цикла значение итеративной переменной цикла не определено, если она не указана в опции lastprivate директивы for.
Все эти ограничения введены для того, чтобы компилятор OpenMP мог обеспечить точное определение количества итераций в момент входа в цикл и последующее их распределение между потоками параллельного региона.
Слайд 5Пример неверного использования
директивы for
#include
#include
#include
#define ARRAYSIZE …
int main( ) { //
Пример неверного использования
директивы for
#include
#include
#include
#define ARRAYSIZE …
int main( ) { //
int i, j, tmp, arrayX[ ARRAYSIZE ] ;
for( i = 0; i < ARRAYSIZE; i += 1) {
arrayX[ i ] = rand( );
}
//директивы parallel и for могут быть записаны вместе:
#pragma omp parallel for //для этого цикла неверно!
for( i = 0; i < ARRAYSIZE; i += 1 ) {
//этот вариант тоже неверен:#pragma omp parallel for здесь
for( j = i+1; j < ARRAYSIZE; j++)
if( arrayX[ j ] < arrayX[ i ] ) {
tmp = arrayX[ i ];
arrayX[ i ] = arrayX[ j ];
arrayX[ j ] = tmp;
}
}
…
}
Слайд 6Результаты работы неверной программы пузырьковой сортировки
int arrayX[ ] =
{3, 82, 17,
Результаты работы неверной программы пузырьковой сортировки
int arrayX[ ] =
{3, 82, 17,
При количестве потоков 1 или 2 (все хорошо):
3, 3, 4, 5, 6, 7, 8, 9, 15, 15, 17, 26, 27, 32, 33, 39, 41, 42, 44, 44, 55, 56, 63, 65, 73, 74, 74, 82, 82, 84, 88, 91, 93
При количестве потоков 4, первый запуск:
3, 3, 3, 15, 4, 8, 26, 4, 5, 6, 7, 8, 8, 9, 15, 15, 17, 88, 65, 55, 42, 41, 32, 27, 82, 63, 63, 73, 74, 74, 84, 93, 93
второй запуск:
3, 9, 4, 3, 33, 3, 3, 74, 15, 5, 5, 6, 7, 7, 15, 15, 17, 88, 73, 65, 55, 42, 74, 41, 32, 27, 26, 39, 42, 44, 63, 84, 93
Слайд 7Опции директивы for
private( список переменных)
firstprivate( список переменных )
lastprivate( список
Опции директивы for
private( список переменных)
firstprivate( список переменных )
lastprivate( список
reduction( оператор : список переменных )
nowait
schedule( type[ , chunk ] )
ordered
collapse( n )
Слайд 8Опция schedule
schedule( type[ , chunk ] )
Задаёт способ распределения итераций цикла по
Опция schedule
schedule( type[ , chunk ] )
Задаёт способ распределения итераций цикла по
type = static – блочно-циклическое распределение итераций цикла c размером блока chunk. Первый блок из chunk итераций выполняет мастер-поток, второй блок — поток с номером 1 и т.д. до последнего потока, затем распределение снова начинается с нулевого потока. Если значение chunk не указано, то всё множество итераций делится на непрерывные куски примерно одинакового размера (конкретный способ зависит от реализации), и полученные порции итераций распределяются между потоками. Примеры: schedule( static, 16 ), schedule( static )
Пусть есть цикл for( int i =0; i < 256; i++) { … }
#pragma omp for num_threads( 4 ) shedule( static, 16 )
Поток 0 выполнит итерации 0-15, 64-79, 128-143, 192-207.
Поток 1 выполнит итерации 16-31, 80-95, 144-159, 208-223.
…
#pragma omp for num_threads( 4 ) shedule( static)
Поток 0 выполнит итерации 0-63
Поток 1 выполнит итерации 64-127 …
1
Слайд 9Опция schedule
schedule( type[, chunk] )
type = dynamic – динамическое распределение итераций с
Опция schedule
schedule( type[, chunk] )
type = dynamic – динамическое распределение итераций с
Для того же цикла в первом случае (schedule( dynamic )) распределение может оказаться таким:
Поток 0: 0, 6, 8, 13, …
Поток 1: 1, 7, 11, 16, …
Поток 2: 2, 4, 10, 15, …
Поток 3: 3, 5, 9, 12, 14, …
Во втором случае (schedule( dynamic, 4 )), например, таким:
Поток 0: 0-3, 24-27, 8, 48-51, …
Поток 1: 4-7, 20-23, 32-35, 52-55, …
Поток 2: 8-11, 28-31, 36-39, 44-47, …
Поток 3: 12-15, 16-19, 40-43, 56-59, …
2
Слайд 10Опция schedule
schedule( type[, chunk] )
type = guided – динамическое распределение итераций, при
Опция schedule
schedule( type[, chunk] )
type = guided – динамическое распределение итераций, при
Для того же цикла в случае schedule( guided, 4 ) распределение может оказаться таким:
Поток 0: 0-15, 76-87, 121-129, … 244-247
Поток 1: 16-31, 88-99, 130-138, … 252-255
Поток 2: 32-47, 64-75, 139-147, … 248-251
Поток 3: 48-63, 100-111, 112-120, … 240-243
В случае schedule( guided ), например, таким:
Поток 0: 0-15, 64-75, 121-129, … 247, 249
Поток 1: 16-31, 88-99, 112-120, …254, 255
Поток 2: 32-47, 76-87, 130-138, … 251, 252
Поток 3: 48-63, 100-111, 139-147, … 248, 253
3
Слайд 11Опция schedule
schedule( type[, chunk] )
type = auto – способ распределения итераций (static,
Опция schedule
schedule( type[, chunk] )
type = auto – способ распределения итераций (static,
type = runtime – способ распределения итераций выбирается во время работы программы по значению переменной среды OMP_SCHEDULE (которую устанавливает системный администратор, например, так: "dynamic, 8"). Параметр chunk при этом значении опции тоже не задаётся.
4
Слайд 12Опции директивы for
ordered
Эта опция, указывает компилятору, что в теле цикла могут встречаться
Опции директивы for
ordered
Эта опция, указывает компилятору, что в теле цикла могут встречаться
В версии стандарта 3.0 появилась еще одна опция:
collapse( n ), которая указывает компилятору, что n последовательных тесно вложенных циклов ассоциируется с данной директивой:
#pragma omp parallel for collapse( 2 )
for( int i = 0; i < N; i += 1)
for( int j = 0; j < M; j += 1)
…
Для этих циклов образуется общее пространство итераций, которое делится между потоками:
for( int ij = 0; ij < N * M; ij += 1)
…
Если опция collapse не задана, то директива for относится только к одному непосредственно следующему за ней циклу.
Слайд 13Параллельная пузырьковая сортировка
Алгоритм пузырьковой сортировки в прямом виде не может быть распараллелен,
Параллельная пузырьковая сортировка
Алгоритм пузырьковой сортировки в прямом виде не может быть распараллелен,
Суть модификации состоит в том, что в алгоритм сортировки вводятся два разных правила выполнения итераций метода – в зависимости от четности или нечетности номера итерации сортировки для обработки берутся элементы с четными или нечетными индексами соответственно, их сравнение всегда осуществляется с правыми соседними элементами массива.
Таким образом, на всех нечетных итерациях сравниваются пары
(1, 2), (3, 4), ..., (n-1,n) при нечетном n,
а на четных итерациях обрабатываются элементы
(0, 1), (2, 3), ..., (n-2,n-1).
После n-кратного повторения итераций сортировки исходный набор данных оказывается упорядоченным.
Слайд 14Параллельная пузырьковая сортировка
#define compExch( x, y ) if( x > y ){
Параллельная пузырьковая сортировка
#define compExch( x, y ) if( x > y ){
#define SIZE …
double arrayX[ SIZE ] = … ;
int tmp;
…
for ( int i = 0; i < SIZE; i++ ) {
if ( i % 2 == 0) // четная итерация
{
#pragma omp parallel for private( tmp )
for ( int j = 0; j < SIZE - 1; j += 2 ) // (0,1) (2,3) (4,5)…
compExch( arrayX[ j ], arrayX[ j + 1 ] );
}
else // нечетная итерация
{
#pragma omp parallel for private( tmp )
for ( int j = 1; j < SIZE - 1; j += 2 ) // (1,2) (3,4) (5,6)
compExch(arrayX[ j ], arrayX[ j + 1 ] );
}
}
Слайд 15Задачи (tasks)
только начиная с версии 3.0
Синтаксис:
#pragma omp task [опция [[,] опция]...]
block>
Начиная с 3-й версии OpenMP, любой параллелизм (это директивы parallel, parallel for, sections) реализуется в виде «задач», назначаемых потокам исполняющей системой OpenMP. С помощью директивы task любой структурный блок внутри параллельного региона можно объявить как задачу, которая добавляется к списку задач этого региона.
Опции:
if( скалярное выражение )
private( список переменных )
firstprivate( список переменных )
shared( список переменных )
default ( … )
nowait
untied - означает, что в случае откладывания задача может быть продолжена любым потоком из тех, которые выполняют данную параллельную область. Если эта опция не указана, то задача может быть выполнена только породившим ее потоком.
Задачи (tasks)
только начиная с версии 3.0
Синтаксис:
#pragma omp task [опция [[,] опция]...]
Начиная с 3-й версии OpenMP, любой параллелизм (это директивы parallel, parallel for, sections) реализуется в виде «задач», назначаемых потокам исполняющей системой OpenMP. С помощью директивы task любой структурный блок внутри параллельного региона можно объявить как задачу, которая добавляется к списку задач этого региона.
Опции:
if( скалярное выражение )
private( список переменных )
firstprivate( список переменных )
shared( список переменных )
default ( … )
nowait
untied - означает, что в случае откладывания задача может быть продолжена любым потоком из тех, которые выполняют данную параллельную область. Если эта опция не указана, то задача может быть выполнена только породившим ее потоком.
Слайд 16Пример использования директивы task
struct node
{
struct node *left;
struct node *right;
dataType data;
};
extern void process( struct node * );
void traverse( struct node *p )
{
if (p->left)
#pragma omp task firstprivate(p) untied
Пример использования директивы task
struct node
{
struct node *left;
struct node *right;
dataType data;
};
extern void process( struct node * );
void traverse( struct node *p )
{
if (p->left)
#pragma omp task firstprivate(p) untied
Слайд 17Директивы taskwait и taskyeld
#pragma omp taskwait
Поток, выполнивший эту директиву, приостанавливается до тех пор,
Директивы taskwait и taskyeld
#pragma omp taskwait
Поток, выполнивший эту директиву, приостанавливается до тех пор,
Например, как написано в примере, эта директива присутствует перед вызовом функции process. Это гарантирует, что и левое и правое поддерево будут полностью обработаны до обработки корня (но последовательность «левое-правое» или «правое-левое» останется непредсказуемой)
#pragma omp taskyield
Директива taskyield указывает, что текущая задача может быть приостановлена в пользу выполнения других задач.
Слайд 18Группа директив синхронизации
Синхронизация работы потоков в OpenMP может выполняться и явно и
Группа директив синхронизации
Синхронизация работы потоков в OpenMP может выполняться и явно и
Неявная синхронизация выполняется в конце любой параллельной области при условии, что в момент создания этой области не была указана опция nowait.
В некоторых случаях программисту может потребоваться явно указать необходимость остановки всех или некоторых потоков программы вплоть до момента наступления ожидаемого события.
Барьерная синхронизация
Самый распространенный способ синхронизации в OpenMP – барьерный.
Синтаксис:
#pragma omp barrier