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

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


Скачать 0.55 Mb.
НазваниеС. антоновпараллельноепрограммированиесиспользованиемтехнологииopenMP
Дата03.04.2022
Размер0.55 Mb.
Формат файлаpdf
Имя файлаOpenMP.pdf
ТипУчебное пособие
#438994
страница3 из 8
1   2   3   4   5   6   7   8
omp_get_dynamic()
. Сначала распечатывается значение, полученное функ- цией
omp_get_dynamic()
– это позволяет узнать значение переменной
OMP_DYNAMIC
по умолчанию.
Затем при помощи функции
omp_set_dynamic()
переменная
OMP_DYNAMIC
устанавливается в
true
, что подтверждает выдача ещё один раз значения функции
omp_get_dynamic()
Затем порождается параллельная область, выполняемая заданным количест- вом нитей (
128
). В параллельной области печатается реальное число выпол- няющих её нитей. Директива
master
позволяет обеспечить печать только процессом-мастером. В системах с динамическим изменением числа нитей выданное значение может отличаться от заданного (
128
).

20
#include
#include
int main(int argc, char *argv[])
{
printf("
Значение
OMP_DYNAMIC: %d\n", omp_get_dynamic());
omp_set_dynamic(1);
printf("
Значение
OMP_DYNAMIC: %d\n", omp_get_dynamic());
#pragma omp parallel num_threads(128)
{
#pragma omp master
{
printf("
Параллельная область
, %d
нитей
\n",
omp_get_num_threads());
}
}
}
Пример 6a. Функции omp_set_dynamic() и omp_get_dynamic() наязыкеСи.
program example6b
include "omp_lib.h"
print *, "
Значение
OMP_DYNAMIC: ", omp_get_dynamic()
call omp_set_dynamic(.TRUE.)
print *, "
Значение
OMP_DYNAMIC: ", omp_get_dynamic()
!$omp parallel num_threads(128)
!$omp master
print *, "
Параллельная область
,", omp_get_num_threads(),
& "
нитей
"
!$omp end master
!$omp end parallel
end
Пример 6b. Функции omp_set_dynamic() и omp_get_dynamic() наязыкеФор-
тран.
Функция
omp_get_max_threads()
возвращает максимально допустимое чис- ло нитей для использования в следующей параллельной области.
Си:
int omp_get_max_threads(void);
Фортран:
integer function omp_get_max_threads()
Функция
omp_get_num_procs()
возвращает количество процессоров, дос- тупных для использования программе пользователя на момент вызова. Нуж- но учитывать, что количество доступных процессоров может динамически изменяться.
Си:
int omp_get_num_procs(void);

21
Фортран:
integer function omp_get_num_procs()
Параллельные области могут быть вложенными; по умолчанию вложенная параллельная область выполняется одной нитью. Это управляется установ- кой переменной среды
OMP_NESTED
. Например, в Linux в командной оболочке bash разрешить вложенный параллелизм можно при помощи следующей ко- манды:
export OMP_NESTED=true
Изменить значение переменной
OMP_NESTED
можно с помощью вызова функ- ции
omp_set_nested()
Си:
void omp_set_nested(int nested)
Фортран:
subroutine omp_set_nested(nested)
logical nested
Функция
omp_set_nested()
разрешает или запрещает вложенный паралле- лизм. На языке Си в качестве значения параметра задаётся
0
или
1
, а на языке
Фортран –
.FALSE.
или
.TRUE.
Если вложенный параллелизм разрешён, то каждая нить, в которой встретится описание параллельной области, породит для её выполнения новую группу нитей. Сама породившая нить станет в но- вой группе нитью-мастером. Если система не поддерживает вложенный па- раллелизм, данная функция не будет иметь эффекта.
Пример 7 демонстрирует использование вложенных параллельных областей и функции
omp_set_nested()
. Вызов функции
omp_set_nested()
перед первой частью разрешает использование вложенных параллельных областей.
Для определения номера нити в текущей параллельной секции используются вызовы функции
omp_get_thread_num()
. Каждая нить внешней параллель- ной области породит новые нити, каждая из которых напечатает свой номер вместе с номером породившей нити. Далее вызов
omp_set_nested()
запре- щает использование вложенных параллельных областей. Во второй части вложенная параллельная область будет выполняться без порождения новых нитей, что и видно по получаемой выдаче.

22
#include
#include
int main(int argc, char *argv[])
{
int n;
omp_set_nested(1);
#pragma omp parallel private(n)
{
n=omp_get_thread_num();
#pragma omp parallel
{
printf("
Часть
1,
нить
%d - %d\n", n,
omp_get_thread_num());
}
}
omp_set_nested(0);
#pragma omp parallel private(n)
{
n=omp_get_thread_num();
#pragma omp parallel
{
printf("
Часть
2,
нить
%d - %d\n", n,
omp_get_thread_num());
}
}
}
Пример 7a. ВложенныепараллельныеобластинаязыкеСи.
program example7b
include "omp_lib.h"
integer n
call omp_set_nested(.TRUE.)
!$omp parallel private(n)
n=omp_get_thread_num()
!$omp parallel
print *, "
Часть
1,
нить
", n, " - ",
& omp_get_thread_num()
!$omp end parallel
!$omp end parallel
call omp_set_nested(.FALSE.)
!$omp parallel private(n)
n=omp_get_thread_num()
!$omp parallel
print *, "
Часть
2,
нить
", n, " - ",
& omp_get_thread_num()
!$omp end parallel
!$omp end parallel
end
Пример 7b. ВложенныепараллельныеобластинаязыкеФортран.
Узнать значение переменной
OMP_NESTED
можно при помощи функции
omp_get_nested()

23
Си:
int omp_get_nested(void);
Фортран:
logical function omp_get_nested()
Функция
omp_in_parallel()
возвращает
1
(
.TRUE.
для языка Фортран), ес- ли она была вызвана из активной параллельной области программы.
Си:
int omp_in_parallel(void);
Фортран:
logical function omp_in_parallel()
Пример 8 иллюстрирует применение функции
omp_in_parallel()
. Функция
mode
демонстрирует изменение функциональности в зависимости от того, вызвана она из последовательной или из параллельной области. В последова- тельной области будет напечатано
"
Последовательная область
"
, а в парал- лельной –
"
Параллельная область
"
#include
#include
void mode(void){
if(omp_in_parallel()) printf("
Параллельная область
\n");
else printf("
Последовательная область
\n");
}
int main(int argc, char *argv[])
{
mode();
#pragma omp parallel
{
#pragma omp master
{
mode();
}
}
}
Пример 8a. Функция omp_in_parallel() наязыкеСи.

24
program example8b
call mode()
!$omp parallel
!$omp master
call mode()
!$omp end master
!$omp end parallel
end
subroutine mode()
include "omp_lib.h"
if(omp_in_parallel()) then
print *, "
Параллельная область
"
else
print *, "
Последовательная область
"
end if
end
Пример 8b. Функция omp_in_parallel() наязыкеФортран.
Директива
single
Если в параллельной области какой-либо участок кода должен быть выпол- нен лишь один раз, то его нужно выделить директивами
single
(
single ...
end single
).
Си:
#pragma omp single [
опция
[[,]
опция
]...]
Фортран:
!$omp single [
опция
[[,]
опция
]...]
<
код для одной нити
>
!$omp end single [
опция
[[,]
опция
]...]
Возможные опции:

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

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

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

25 переменные списка не должны быть перечислены в опциях
private
и
firstprivate
данной директивы
single
;

nowait
– после выполнения выделенного участка происходит неявная барьерная синхронизация параллельно работающих нитей: их даль- нейшее выполнение происходит только тогда, когда все они достигнут данной точки; если в подобной задержке нет необходимости, опция
nowait
позволяет нитям, уже дошедшим до конца участка, продолжить выполнение без синхронизации с остальными.
В программах на языке Си все опции указываются у директивы
single
, а в программах на языке Фортран опции
private
и
firstprivate
относятся к директиве
single
, а опции
copyprivate
и
nowait
– к директиве
end single
Какая именно нить будет выполнять выделенный участок программы, не специфицируется. Одна нить будет выполнять данный фрагмент, а все ос- тальные нити будут ожидать завершения её работы, если только не указана опция
nowait
. Необходимость использования директивы
single
часто воз- никает при работе с общими переменными.
Пример 9 иллюстрирует применение директивы
single
вместе с опцией
nowait
. Сначала все нити напечатают текст
"
Сообщение
1"
, при этом одна нить (не обязательно нить-мастер) дополнительно напечатает текст
"
Одна нить
"
. Остальные нити, не дожидаясь завершения выполнения области
sin-
gle
, напечатают текст
"
Сообщение
2"
. Таким образом, первое появление
"
Сообщение
2"
в выводе может встретиться как до текста
"
Одна нить
"
, так и после него. Если убрать опцию
nowait
, то по окончании области
single
произойдёт барьерная синхронизация, и ни одна выдача
"
Сообщение
2"
не может появиться до выдачи
"
Одна нить
"
#include
int main(int argc, char *argv[])
{
#pragma omp parallel
{
printf("
Сообщение
1\n");
#pragma omp single nowait
{
printf("
Одна нить
\n");
}
printf("
Сообщение
2\n");
}
}
Пример 9a. Директива single иопция nowait наязыкеСи.

26
program example9b
!$omp parallel
print *, "
Сообщение
1"
!$omp single
print *, "
Одна нить
"
!$omp end single nowait
print *, "
Сообщение
2"
!$omp end parallel
end
Пример 9b. Директива single иопция nowait наязыкеФортран.
Пример 10 иллюстрирует применение опции
copyprivate
. В данном приме- ре переменная
n
объявлена в параллельной области как локальная. Каждая нить присвоит переменной
n
значение, равное своему порядковому номеру, и напечатает данное значение. В области
single
одна из нитей присвоит пере- менной
n
значение
100
, и на выходе из области это значение будет присвоено переменной
n
на всех нитях. В конце параллельной области значение
n
печа- тается ещё раз и на всех нитях оно равно
100
#include
#include
int main(int argc, char *argv[])
{
int n;
#pragma omp parallel private(n)
{
n=omp_get_thread_num();
printf("
Значение
n (
начало
): %d\n", n);
#pragma omp single copyprivate(n)
{
n=100;
}
printf("
Значение
n (
конец
): %d\n", n);
}
}
Пример 10a. Опция copyprivate наязыкеСи.
program example10b
include "omp_lib.h"
integer n
!$omp parallel private(n)
n=omp_get_thread_num()
print *, "
Значение
n (
начало
): ", n
!$omp single
n=100;
!$omp end single copyprivate(n)
print *, "
Значение
n (
конец
): ", n
!$omp end parallel
end
Пример 10b. Опция copyprivate наязыкеФортран.

27
Директива
master
Директивы
master
(
master ... end master
) выделяют участок кода, кото- рый будет выполнен только нитью-мастером. Остальные нити просто про- пускают данный участок и продолжают работу с оператора, расположенного следом за ним. Неявной синхронизации данная директива не предполагает.
Си:
#pragma omp master
Фортран:
!$omp master
<
код для нити
-
мастера
>
!$omp end master
Пример 11 демонстрирует применение директивы
master
. Переменная
n
яв- ляется локальной, то есть каждая нить работает со своим экземпляром. Сна- чала все нити присвоят переменной
n
значение
1
. Потом нить-мастер присво- ит переменной
n
значение
2
, и все нити напечатают значение
n
. Затем нить- мастер присвоит переменной
n
значение
3
, и снова все нити напечатают зна- чение
n
. Видно, что директиву
master
всегда выполняет одна и та же нить. В данном примере все нити выведут значение
1
, а нить-мастер сначала выведет значение
2
, а потом - значение
3
#include
int main(int argc, char *argv[])
{
int n;
#pragma omp parallel private(n)
{
n=1;
#pragma omp master
{
n=2;
}
printf("
Первое значение
n: %d\n", n);
#pragma omp barrier
#pragma omp master
{
n=3;
}
printf("
Второе значение
n: %d\n", n);
}
}
Пример 11a. Директива master наязыкеСи.

28
program example11b
integer n
!$omp parallel private(n)
n=1
!$omp master
n=2
!$omp end master
print *, "
Первое значение
n: ", n
!$omp barrier
!$omp master
n=3;
!$omp end master
print *, "
Второе значение
n: ", n
!$omp end parallel
end
Пример 11b. Директива master наязыкеФортран.
Задания

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

В каких случаях может быть необходимо использование опции
if
ди- рективы
parallel
?

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

При помощи трёх уровней вложенных параллельных областей породи- те 8 нитей (на каждом уровне параллельную область должны испол- нять 2 нити). Посмотрите, как будет исполняться программа, если за- претить вложенные параллельные области.

Чем отличаются директивы
single
и
master
?

Может ли нить-мастер выполнить область, ассоциированную с дирек- тивой
single
?

Может ли нить с номером
1
выполнить область, ассоциированную с директивой
master
?

29
Модель данных
Модель данных в OpenMP предполагает наличие как общей для всех нитей области памяти, так и локальной области памяти для каждой нити.
В OpenMP переменные в параллельных областях программы разделяются на два основных класса:

shared
(общие; все нити видят одну и ту же переменную);

private
(локальные, приватные; каждая нить видит свой экземпляр данной переменной).
Общая переменная всегда существует лишь в одном экземпляре для всей об- ласти действия и доступна всем нитям под одним и тем же именем. Объявле- ние локальной переменной вызывает порождение своего экземпляра данной переменной (того же типа и размера) для каждой нити. Изменение нитью значения своей локальной переменной никак не влияет на изменение значе- ния этой же локальной переменной в других нитях.
Если несколько переменных одновременно записывают значение общей пе- ременной без выполнения синхронизации или если как минимум одна нить читает значение общей переменной и как минимум одна нить записывает значение этой переменной без выполнения синхронизации, то возникает си- туация так называемой «гонкиданных» (data race), при которой результат выполнения программы непредсказуем.
По умолчанию, все переменные, порождённые вне параллельной области, при входе в эту область остаются общими (
1   2   3   4   5   6   7   8


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