Главная страница

С. антоновпараллельноепрограммированиесиспользованиемтехнологииopenMP


Скачать 0.55 Mb.
НазваниеС. антоновпараллельноепрограммированиесиспользованиемтехнологииopenMP
Дата03.04.2022
Размер0.55 Mb.
Формат файлаpdf
Имя файлаOpenMP.pdf
ТипУчебное пособие
#438994
страница6 из 8
1   2   3   4   5   6   7   8
#pragma omp sections [
опция
[[,]
опция
]...]

48
Фортран:
!$omp sections [
опция
[[,]
опция
]...]
<
блок секций
>
!$omp end sections [nowait]
Эта директива определяет набор независимых секций кода, каждая из кото- рых выполняется своей нитью.
Возможные опции:

private(
список
)
– задаёт список переменных, для которых порожда- ется локальная копия в каждой нити; начальное значение локальных копий переменных из списка не определено;

firstprivate(
список
)
– задаёт список переменных, для которых по- рождается локальная копия в каждой нити; локальные копии перемен- ных инициализируются значениями этих переменных в нити-мастере;

lastprivate(
список
)
– переменным, перечисленным в списке, при- сваивается результат, полученный в последней секции;

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

nowait
– в конце блока секций происходит неявная барьерная синхро- низация параллельно работающих нитей: их дальнейшее выполнение происходит только тогда, когда все они достигнут данной точки; если в подобной задержке нет необходимости, опция
nowait
позволяет нитям, уже дошедшим до конца своих секций, продолжить выполнение без синхронизации с остальными.
Директива
section
задаёт участок кода внутри секции
sections
для выпол- нения одной нитью.
Си:
#pragma omp section

49
Фортран:
!$omp section
Перед первым участком кода в блоке
sections
директива
section
не обяза- тельна. Какие именно нити будут задействованы для выполнения какой сек- ции, не специфицируется. Если количество нитей больше количества секций, то часть нитей для выполнения данного блока секций не будет задействова- на. Если количество нитей меньше количества секций, то некоторым (или всем) нитям достанется более одной секции.
Пример 21 иллюстрирует применение директивы
sections
. Cначала три ни- ти, на которые распределились три секции
section
, выведут сообщение со своим номером, а потом все нити напечатают одинаковое сообщение со сво- им номером.
#include
#include
int main(int argc, char *argv[])
{
int n;
#pragma omp parallel private(n)
{
n=omp_get_thread_num();
#pragma omp sections
{
#pragma omp section
{
printf("
Первая секция
,
процесс
%d\n", n);
}
#pragma omp section
{
printf("
Вторая секция
,
процесс
%d\n", n);
}
#pragma omp section
{
printf("
Третья секция
,
процесс
%d\n", n);
}
}
printf("
Параллельная область
,
процесс
%d\n", n);
}
}
Пример 21a. Директива sections наязыкеСи.

50
program example21b
include "omp_lib.h"
integer n
!$omp parallel private(n)
n=omp_get_thread_num()
!$omp sections
!$omp section
print *, "
Первая секция
,
процесс
", n
!$omp section
print *, "
Вторая секция
,
процесс
", n
!$omp section
print *, "
Третья секция
,
процесс
", n
!$omp end sections
print *, "
Параллельная область
,
процесс
", n
!$omp end parallel
end
Пример 21b. Директива sections наязыкеФортран.
Пример 22 демонстрирует использование опции
lastprivate
. В данном примере опция
lastprivate
используется вместе с директивой
sections
Переменная
n
объявлена как
lastprivate
переменная. Три нити, выпол- няющие секции
section
, присваивают своей локальной копии
n
разные зна- чения. По выходе из области
sections
значение
n
из последней секции при- сваивается локальным копиям во всех нитях, поэтому все нити напечатают число
3
. Это же значение сохранится для переменной
n
и в последовательной области.

51
#include
#include
int main(int argc, char *argv[])
{
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
на нити
%d: %d\n",
omp_get_thread_num(), n);
}
printf("
Значение
n
в последовательной области
: %d\n", n);
}
Пример 22a. Опция lastprivate наязыкеСи.
program example22b
include "omp_lib.h"
integer n
n=0
!$omp parallel
!$omp sections lastprivate(n)
!$omp section
n=1;
!$omp section
n=2;
!$omp section
n=3;
!$omp end sections
print *, "
Значение
n
на нити
",
& omp_get_thread_num(), ": ", n
!$omp end parallel
print *, "
Значение
n
в последовательной области
: ", n
end
Пример 22b. Опция lastprivate наязыкеФортран.

52
Директива
workshare
Директива
workshare ... end workshare
используется для задания конеч- ного (неитеративного) параллелизма программ, написанных на языке Фор- тран.
!$omp workshare
<
блок операторов
>
!$omp end workshare [nowait]
Блок между директивами определяет набор независимых операторов, каждый из которых выполняется своей нитью. В этот набор могут входить: присваи- вания массивов и скалярных переменных, операторы и конструкции
FORALL
,
WHERE
, директивы
atomic
,
critical
,
parallel
. При выполнении этого набо- ра команд каждая такая операция выдаётся на исполнение отдельной нити
(распределение операций по нитям зависит от реализации), при этом система поддержки автоматически вставляет все необходимые по семантике синхро- низации. Например, система обеспечивает, чтобы операция не начиналась до тех пор, пока не будут полностью готовы все её аргументы. В конце конст- рукции предполагается неявная синхронизация работы нитей. Если в подоб- ной синхронизации нет необходимости, то может быть использована опция
nowait
Пример 23 иллюстрирует применение директивы
workshare
. Сначала два исходных массива инициализируются, затем в параллельной области задаёт- ся область
workshare
, в которой производятся три массивные операции.
Системой гарантируется, что третья операция не начнётся до того момента, пока не завершатся первые две.
program example23
real a(10), b(10), c(10), d(10), e(10)
integer i
do i=1, 10
a(i) = i
b(i) = 2*i
end do
!$omp parallel shared(a, b, c, d, e)
!$omp workshare
c=a+b
d=b-a
e=c+2*d
!$omp end workshare
!$omp end parallel
print *, "
Результирующий массив
: ", e
end
Пример 23. Директива workshare.

53
Задачи
(
tasks
)
Директива
task
(
task ... end task
) применяется для выделения отдель- ной независимой задачи.
Си:
#pragma omp task [
опция
[[,]
опция
]...]
Фортран:
!$omp task [
опция
[[,]
опция
]...]
<
код задачи
>
!$omp end task
Текущая нить выделяет в качестве задачи ассоциированный с директивой блок операторов. Задача может выполняться немедленно после создания или быть отложенной на неопределённое время и выполняться по частям. Размер таких частей, а также порядок выполнения частей разных отложенных задач определяется реализацией.
Возможные опции:

if(
условие
)
— порождение новой задачи только при выполнении не- которого условия; если условие не выполняется, то задача будет вы- полнена текущей нитью и немедленно;

untied
— опция означает, что в случае откладывания задача может быть продолжена любой нитью из числа выполняющих данную парал- лельную область; если данная опция не указана, то задача может быть продолжена только породившей её нитью;

default(private|firstprivate|shared|none)
– всем переменным в задаче, которым явно не назначен класс, будет назначен класс
private
,
firstprivate
или
shared
соответственно;
none
означает, что всем пе- ременным в задаче класс должен быть назначен явно; в языке Си зада- ются только варианты
shared
или
none
;

private(
список
)
– задаёт список переменных, для которых порожда- ется локальная копия в каждой нити; начальное значение локальных копий переменных из списка не определено;

firstprivate(
список
)
– задаёт список переменных, для которых по- рождается локальная копия в каждой нити; локальные копии перемен- ных инициализируются значениями этих переменных в нити-мастере;

shared(
список
)
– задаёт список переменных, общих для всех нитей.

54
Для гарантированного завершения в точке вызова всех запущенных задач ис- пользуется директива
taskwait
Си:
#pragma omp taskwait
Фортран:
!$omp taskwait
Нить, выполнившая данную директиву, приостанавливается до тех пор, пока не будут завершены все ранее запущенные данной нитью независимые зада- чи.
Задания

Могут ли функции
omp_get_thread_num()
и
omp_get_num_threads()
вернуть одинаковые значения на нескольких нитях одной параллель- ной области?

Можно ли распределить между нитями итерации цикла без использо- вания директивы
for
(
do ... [end do]
)?

Можно ли одной директивой распределить между нитями итерации сразу нескольких циклов?

Возможно ли, что при статическом распределении итераций цикла ни- тям достанется разное количество итераций?

Могут ли при повторном запуске программы итерации распределяемо- го цикла достаться другим нитям? Если да, то при каких способах рас- пределения итераций?

Для чего может быть полезно указывать параметр
chunk
при способе распределения итераций
guided
?

Можно ли реализовать параллельные секции без использования дирек- тив
sections
(
sections ... end sections
) и
section
?

Как при выходе из параллельных секций разослать значение некоторой локальной переменной всем нитям, выполняющим данную параллель- ную область?

В каких случаях может пригодиться механизм задач?

Напишите параллельную программу, реализующую скалярное произ- ведение двух векторов.

Напишите параллельную программу, реализующую поиск максималь- ного значения вектора.

55
Синхронизация
Целый набор директив в OpenMP предназначен для синхронизации работы нитей.
Барьер
Самый распространенный способ синхронизации в OpenMP – барьер. Он оформляется с помощью директивы
barrier
Си:
#pragma omp barrier
Фортран:
!$omp barrier
Нити, выполняющие текущую параллельную область, дойдя до этой дирек- тивы, останавливаются и ждут, пока все нити не дойдут до этой точки про- граммы, после чего разблокируются и продолжают работать дальше. Кроме того, для разблокировки необходимо, чтобы все синхронизируемые нити за- вершили все порождённые ими задачи (
task
).
Пример 24 демонстрирует применение директивы
barrier
. Директива
bar-
rier
используется для упорядочивания вывода от работающих нитей. Выда- чи с разных нитей
"
Сообщение
1"
и
"
Сообщение
2"
могут перемежаться в произвольном порядке, а выдача
"
Сообщение
3"
со всех нитей придёт строго после двух предыдущих выдач.
#include
#include
int main(int argc, char *argv[])
{
#pragma omp parallel
{
printf("
Сообщение
1\n");
printf("
Сообщение
2\n");
#pragma omp barrier
printf("
Сообщение
3\n");
}
}
Пример 24a. Директива barrier наязыкеСи.

56
program example24b
include "omp_lib.h"
!$omp parallel
print *, "
Сообщение
1"
print *, "
Сообщение
2"
!$omp barrier
print *, "
Сообщение
3"
!$omp end parallel
end
Пример 24b. Директива barrier наязыкеФортран.
Директива
ordered
Директивы
ordered
(
ordered ... end ordered
) определяют блок внутри тела цикла, который должен выполняться в том порядке, в котором итерации идут в последовательном цикле.
Си:
#pragma omp ordered
Фортран:
!$omp ordered
<
блок операторов
>
!$omp end ordered
Блок операторов относится к самому внутреннему из объемлющих циклов, а в параллельном цикле должна быть задана опция
ordered
. Нить, выполняю- щая первую итерацию цикла, выполняет операции данного блока. Нить, вы- полняющая любую следующую итерацию, должна сначала дождаться вы- полнения всех операций блока всеми нитями, выполняющими предыдущие итерации. Может использоваться, например, для упорядочения вывода от па- раллельных нитей.
Пример 25 иллюстрирует применение директивы
ordered
и опции
ordered
Цикл
for
(
do
) помечен как
ordered
. Внутри тела цикла идут две выдачи – одна вне блока
ordered
, а вторая – внутри него. В результате первая выдача получается неупорядоченной, а вторая идёт в строгом порядке по возраста- нию номера итерации.

57
#include
#include
int main(int argc, char *argv[])
{
int i, n;
#pragma omp parallel private (i, n)
{
n=omp_get_thread_num();
#pragma omp for ordered
for (i=0; i<5; i++)
{
printf("
Нить
%d,
итерация
%d\n", n, i);
#pragma omp ordered
{
printf("ordered:
Нить
%d,
итерация
%d\n", n, i);
}
}
}
}
Пример 25a. Директива ordered иопция ordered наязыкеСи.
program example25b
include "omp_lib.h"
integer i, n;
!$omp parallel private (i, n)
n=omp_get_thread_num();
!$omp do ordered
do i=0, 4
print *, "
Нить
", n, ",
итерация
", i
!$omp ordered
print *, "ordered:
Нить
", n, ",
итерация
", i
!$omp end ordered
end do
!$omp end parallel
end
Пример 25b. Директива ordered иопция ordered наязыкеФортран.
Критические секции
С помощью директив
critical
(
critical ... end critical
) оформляется критическая секция программы.
Си:
#pragma omp critical [(<
имя
_
критической
_
секции
>)]
Фортран:
!$omp critical [(
имя
)]
<
код критической секции
>
!$omp end critical [(
имя
)]

58
В каждый момент времени в критической секции может находиться не более одной нити. Если критическая секция уже выполняется какой-либо нитью, то все другие нити, выполнившие директиву для секции с данным именем, бу- дут заблокированы, пока вошедшая нить не закончит выполнение данной критической секции. Как только работавшая нить выйдет из критической секции, одна из заблокированных на входе нитей войдет в неё. Если на входе в критическую секцию стояло несколько нитей, то случайным образом выби- рается одна из них, а остальные заблокированные нити продолжают ожида- ние.
Все неименованные критические секции условно ассоциируются с одним и тем же именем. Все критические секции, имеющие одно и тоже имя, рас- сматриваются единой секцией, даже если находятся в разных параллельных областях. Побочные входы и выходы из критической секции запрещены.
Пример 26 иллюстрирует применение директивы
1   2   3   4   5   6   7   8


написать администратору сайта