Синтаксис директивы parallel

Содержание

Слайд 2

ОПЦИЯ COLLAPSE collapse(n) — n последовательных тесновложенных циклов ассоциируется с данной

ОПЦИЯ COLLAPSE

collapse(n) — n последовательных тесновложенных циклов ассоциируется с данной директивой.

Для циклов образуется общее пространство итераций, которое делится между тредами.
Если опция не задана, то директива относится только к одному - непосредственно следующему за ней циклу.
Слайд 3

ОПЦИЯ ORDERED Опция для указания о том, что в цикле могут

ОПЦИЯ ORDERED

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

директивы ordered.
В этом случае определяется блок внутри тела цикла, который должен выполняться в порядке, установленном в последовательном цикле
Слайд 4

ОПЦИЯ NOWAIT По умолчанию в конце параллельного цикла происходит неявная барьерная

ОПЦИЯ NOWAIT

По умолчанию в конце параллельного цикла происходит неявная барьерная синхронизация

параллельно работающих тредов – дальнейшее выполнение происходит только тогда, когда все треды достигнут данной точки (барьера).
Если подобная задержка не нужна, используют опцию nowait.
Это позволяет тредам, уже дошедшим до конца цикла, продолжить выполнение без синхронизации с остальными тредами.
Слайд 5

ПРИМЕР #include #define CHUNKSIZE 100 #define N 1000 main () {

ПРИМЕР

#include
#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
}
Слайд 6

ЗАКЛЮЧЕНИЕ ПО РАСПАРАЛЛЕЛИВАНИЮ ЦИКЛОВ При распараллеливании цикла надо убедиться в том,

ЗАКЛЮЧЕНИЕ ПО РАСПАРАЛЛЕЛИВАНИЮ ЦИКЛОВ

При распараллеливании цикла надо убедиться в том, что

итерации данного цикла не имеют информационных зависимостей.
Если цикл не содержит зависимостей, его итерации можно выполнять в любом порядке, в том числе параллельно.
Соблюдение этого требования компилятор не проверяет, вся ответственность - на программисте.
Если дать указание компилятору распараллелить цикл, содержащий зависимости, результат работы программы может оказаться некорректным.
Задание – подобрать пример такого цикла, проверить выполнение параллельной программы.
Слайд 7

ДИРЕКТИВА SECTIONS Используется для реализации функционального параллелизма. Эта директива определяет набор

ДИРЕКТИВА SECTIONS

Используется для реализации функционального параллелизма.
Эта директива определяет набор независимых секций

кода, каждая из которых выполняется своим тредом.
Слайд 8

СИНТАКСИС ДИРЕКТИВЫ SECTIONS #pragma omp sections [опции ...] newline private (list)

СИНТАКСИС ДИРЕКТИВЫ SECTIONS

#pragma omp sections [опции ...] newline
private (list)
firstprivate

(list)
lastprivate (list)
reduction (operator: list)
nowait
{
#pragma omp section newline
structured_block //отдельный тред
#pragma omp section newline
structured_block //отдельный тред

}
Слайд 9

ПРИМЕР int main() { int n; #pragma omp parallel private(n) {

ПРИМЕР

int main()
{ int n;
#pragma omp parallel private(n)
{ n=omp_get_thread_num();
#pragma omp sections
{
#pragma omp section
{ printf("section1, thread

%d\n", n);
}
#pragma omp section
{ printf("section2, thread %d\n", n);
}
#pragma omp section
{ printf("section3, thread %d\n", n);
}
}
printf("parallel region, thread %d\n", n);
}
}
Слайд 10

Перед первым участком кода в блоке sections директива section не обязательна.

Перед первым участком кода в блоке sections директива section не обязательна.


Какие треды будут выполнять какую секцию, не определено.
Если число тредов больше количества секций, то часть тредов для выполнения данного блока секций не будет задействована.
Если число тредов меньше количества секций, то некоторым тредам достанется более одной секции.

ОСОБЕННОСТИ ВЫПОЛНЕНИЯ

Слайд 11

Опция lastprivate определенно связана с последней section: int n=0; #pragma omp

Опция lastprivate определенно связана с последней section:
int n=0;
#pragma omp parallel
{ #pragma omp

sections lastprivate(n)
{ #pragma omp section
{ n=1;
}
#pragma omp section
{ n=2;
}
#pragma omp section
{ n=3;
}
}
printf(«n on thread%d: %d\n", omp_get_thread_num(), n);
}
printf(«n out of parallel region: %d\n", n);

ОСОБЕННОСТИ ВЫПОЛНЕНИЯ

Слайд 12

Переменная n объявлена как lastprivate. Три треда, выполняющие секции section, присваивают

Переменная n объявлена как lastprivate.
Три треда, выполняющие секции section, присваивают

своей локальным копиям n разные значения.
По выходе из области sections значение n из последней секции присваивается локальным копиям во всех тредах.
Поэтому все треды напечатают число 3.
Это же значение сохранится для переменной n и в последовательной области.

ОСОБЕННОСТИ ВЫПОЛНЕНИЯ

Слайд 13

С. – ожидание одних (выполняющихся тредов) другими (уже выполненными). С. действует

С. – ожидание одних (выполняющихся тредов) другими (уже выполненными).
С. действует в

некоторых случаях (см. ранее for, sections) по умолчанию.
Опция nowait отменяет ожидание.
Самый распространенный способ синхронизации в OpenMP – барьер.

СИНХРОНИЗАЦИЯ

Слайд 14

Синтаксис директивы: #pragma omp barrier Треды, выполняющие текущую параллельную область, дойдя

Синтаксис директивы:
#pragma omp barrier
Треды, выполняющие текущую параллельную область, дойдя до этой

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

ДИРЕКТИВА BARRIER

Слайд 15

#pragma omp parallel { printf("Message 1\n"); printf("Message 2\n"); #pragma omp barrier

#pragma omp parallel
{
printf("Message 1\n");
printf("Message 2\n");
#pragma omp barrier
printf("Message 3\n");
}
Выдачи разных тредов Message

1 и Message 2 могут появиться в произвольном порядке.
Выдача Message 3 со всех тредов придёт строго после двух предыдущих выдач.

ПРИМЕР – СИНХРОНИЗАЦИЯ ПЕЧАТИ

Слайд 16

Синтаксис директивы: #pragma omp ordered { ... } Директива определяет блок

Синтаксис директивы:
#pragma omp ordered
{
...
}
Директива определяет блок внутри параллельного цикла, который должен

выполняться в том порядке, в котором итерации шли бы в последовательном цикле.
Директива for должна содержать опцию ordered

ДИРЕКТИВА ORDERED

Слайд 17

Для вложенных циклов выделенный блок операторов относится к самому внутреннему из

Для вложенных циклов выделенный блок операторов относится к самому внутреннему из

циклов.
Тред, выполняющий первую итерацию цикла, выполняет операции выделенного блока.
Тред, выполняющий k-ую итерацию, должен сначала дождаться выполнения всех операций выделенного блока всеми тредами, выполняющими предыдущие итерации.

ОСОБЕННОСТИ ВЫПОЛНЕНИЯ

Слайд 18

int i, n; omp_set_num_threads(4); #pragma omp parallel private (i, n) {

int i, n;
omp_set_num_threads(4);
#pragma omp parallel private (i, n)
{ n=omp_get_thread_num();
#pragma omp for ordered
for

(i=0; i<5; i++)
{
printf(“Thread %d, iter %d\n", n, i);
#pragma omp ordered
{
printf("ordered:thread %d,iter %d\n",n, i);
}
}
}
Внутри тела цикла идут две выдачи – одна вне блока ordered, а вторая – внутри него.

ПРИМЕР – СИНХРОНИЗАЦИЯ ПЕЧАТИ

Слайд 19

В результате: первая выдача будет неупорядоченной, вторая идёт в порядке по

В результате:
первая выдача будет неупорядоченной,
вторая идёт в порядке по возрастанию

номера итерации.

ПРИМЕР – СИНХРОНИЗАЦИЯ ПЕЧАТИ

Слайд 20

В коде можно выделять критические разделы. С помощью критических разделов можно

В коде можно выделять критические разделы.
С помощью критических разделов можно предотвратить

одновременный доступ к одному сегменту кода (критическому разделу!) из нескольких тредов.
Один тред получает доступ только тогда, когда другие не выполняют данный код.

КРИТИЧЕСКИЕ РАЗДЕЛЫ

Слайд 21

Синтаксис директивы: #pragma omp critical [name] { ... } ДИРЕКТИВА CRITICAL

Синтаксис директивы:
#pragma omp critical [name]
{
...
}

ДИРЕКТИВА CRITICAL

Слайд 22

В каждый момент времени критический раздел может выполнять не более одного

В каждый момент времени критический раздел может выполнять не более одного

треда.
Если критический раздел уже выполняет какой-либо тред, то все другие треды будут заблокированы, пока вошедший тред не закончит выполнение.
Как только работавший тред выйдет из критического раздела, один из заблокированных войдет в него.
Если на входе в критический раздел стояло несколько тредов, то случайным образом выбирается один из них.
Остальные заблокированные треды продолжают ожидание.

ОСОБЕННОСТИ ВЫПОЛНЕНИЯ

Слайд 23

main() { int x; x = 0; #pragma omp parallel shared(x)

main()
{
int x;
x = 0;
#pragma omp parallel shared(x)


{
#pragma omp critical
x = x + 1;
}
// end of parallel section
}

ПРИМЕР – КОРРЕКТНАЯ РАБОТА С ОБЩЕЙ ПЕРЕМЕННОЙ

Слайд 24

Блок выполняется единственным тредом Синтаксис директивы: #pragma omp single [опции ...]

Блок выполняется единственным тредом
Синтаксис директивы:
#pragma omp single [опции ...] newline
private

(list)
firstprivate (list)
copyprivate (list)
nowait
{
structured_block //единственный тред
}

ДИРЕКТИВА SINGLE

Слайд 25

После выполнения треда новые значения переменных списка будут доступны всем одноименным

После выполнения треда новые значения переменных списка будут доступны всем одноименным

частным переменным (private и firstprivate), описанным в начале параллельной области и используемым всеми её тредами.
Опция не может использоваться совместно с опцией nowait.
Переменные списка не могут быть перечислены в опциях private и firstprivate данной директивы single.

ОПЦИЯ COPYPRIVATE

Слайд 26

int n; #pragma omp parallel private(n) { n=omp_get_thread_num(); printf("n (start): %d\n",

int n;
#pragma omp parallel private(n)
{ n=omp_get_thread_num();
printf("n (start): %d\n", n);
#pragma omp single copyprivate(n)
{ n=100;
}
printf("n

(finish): %d\n", n);
}
Каждый тред присвоит переменной n значение, равное своему номеру, и напечатает его.
В области single один из тредов присвоит переменной n значение 100.
На выходе из области это значение будет присвоено переменной n на всех тредах.
В конце параллельной области значение n печатается ещё раз .
На всех тредах n=100.

ПРИМЕР (COPYPRIVATE)

Слайд 27

Блок выполняется единственным master-тредом. Остальные треды пропускают блок и продолжают работу

Блок выполняется единственным master-тредом.
Остальные треды пропускают блок и продолжают работу с

оператора, расположенного за ним.
Неявной синхронизации директива не предполагает.
Синтаксис директивы:
#pragma omp master newline
{
structured_block //master-тред
}

ДИРЕКТИВА MASTER

Слайд 28

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

Используется для корректного обновления общих переменных.
Применяется к отдельному оператору типа присваивания.
Синтаксис

директивы:
#pragma omp atomic
statement_expression

ДИРЕКТИВА ATOMIC

Слайд 29

statement_expression: x op= expr;//составное присваивание x = x op expr; x++;

statement_expression:
x op= expr;//составное присваивание
x = x op expr;
x++;
++x;
x--;
--x;
х – скалярная переменная,


expr – скалярное выражение, в котором не присутствует переменная х.
op - оператор:
+
*
-
/
&
^
|
<<
>>
Слайд 30

На время выполнения оператора блокируется доступ к данной переменной всем запущенным

На время выполнения оператора блокируется доступ к данной переменной всем запущенным

в данный момент тредам, кроме треда, выполняющего операцию.
Атомарной является только работа с переменной в левой части оператора присваивания.
Вычисления в правой части не обязаны быть атомарными

ОСОБЕННОСТИ ВЫПОЛНЕНИЯ

Слайд 31

int count = 0; #pragma omp parallel { #pragma omp atomic

int count = 0;
#pragma omp parallel
{
#pragma omp atomic
count++;
}
printf("number of threads: %d\n",

count);
Чтобы предотвратить одновременное изменение несколькими тредами значения переменной, стоящей в левой части оператора присваивания, используется директива atomic

ПРИМЕР

Слайд 32

Используется для согласования состояния памяти (консистентность). Синтаксис директивы: #pragma omp flush [(list)] ДИРЕКТИВА FLUSH

Используется для согласования состояния памяти (консистентность).
Синтаксис директивы:
#pragma omp flush [(list)]

ДИРЕКТИВА FLUSH

Слайд 33

Значения всех переменных (или переменных из списка), временно хранящиеся в регистрах

Значения всех переменных (или переменных из списка), временно хранящиеся в регистрах

и кэш-памяти текущего треда, будут занесены в основную память.
Все изменения переменных, сделанные тредом во время работы, станут видимы остальным тредам.
Если какая-то информация хранится в буферах вывода, то буферы будут сброшены и т.п.
Операция производится только с данными вызвавшего треда.
Данные, изменявшиеся другими тредами, не затрагиваются.

ОСОБЕННОСТИ ВЫПОЛНЕНИЯ