Нижегородский государственный университет им. Н.И.Лобачевского
Опубликован: 02.10.2012 | Доступ: свободный | Студентов: 1753 / 198 | Длительность: 17:47:00
Специальности: Программист
Лекция 4:

Введение в технологии параллельного программирования (OpenMP)

4.3.1. Управление распределением итераций цикла между потоками

При разном объеме вычислений в разных итерациях цикла желательно иметь возможность управлять распределением итераций цикла между потоками – в OpenMP это обеспечивается при помощи параметра schedule директивы for. Поле type параметра schedule может принимать следующие значения:

  • static – статический способ распределения итераций до начала выполнения цикла. Если поле chunk не указано, то итерации делятся поровну между потоками. При заданном значении chunk итерации цикла делятся на блоки размера chunk и эти блоки распределяются между потоками до начала выполнения цикла.
  • dynamic – динамический способ распределения итераций. До начала выполнения цикла потокам выделяются блоки итераций размера chunk (если поле chunk не указано, то полагается значение chunk = 1). Дальнейшее выделение итераций (также блоками размера chunk) осуществляется в момент завершения потоками своих ранее назначенных итераций.
  • guided – управляемый способ распределения итераций. Данный способ близок к предшествующему варианту, отличие состоит только в том, что начальный размер блоков итераций определяется в соответствии с некоторым параметром среды реализации OpenMP, а затем уменьшается экспоненциально (следующее значение chunk есть некоторая доля предшествующего значения) при каждом новом выделении блока итераций. При этом получаемый размер блока итераций не должен быть меньше значения chunk (если поле chunk не указано, то полагается значение chunk = 1).
  • runtime – способ распределения итераций 3Поле chunk для способа runtime неприменимо. , при котором выбор конкретной схемы (из ранее перечисленных) осуществляется в момент начала выполнения программы в соответствии со значением переменной окружения OMP_SCHEDULE. Так, например, для задания динамического способа при размере блока итераций 3, следует определить:
setenv OMP_SCHEDULE "dynamic,3"
      

Полезность такого варианта очевидна – способ распределения итераций между потоками можно менять, не корректируя при этом код программы (т. е. без повторной компиляции и сборки программы).

Для демонстрации примера использования параметра schedule предположим, что матрица в примере 5.3 имеет верхний треугольный вид – в этом случае объем вычислений для каждой строки является различным и последовательное распределение итераций поровну приведет к неравномерному распределению вычислительной нагрузки между потоками. Для балансировки расчетов можно применить статическую или динамическую схемы распределения итераций:

#include <omp.h>
#define NMAX 1000 
main () { 
 int i, j, sum; 
 float a[NMAX][NMAX]; 
 <инициализация данных>
 #pragma omp parallel for shared(a) \
 private(i,j,sum) schedule (dynamic, CHUNK)
 { 

  for (i=0; i < NMAX; i++) {
    sum = 0; 
    for (j=i; j < NMAX; j++) 
      sum += a[i][j]; 

    printf ("Сумма строки %d равна %f\n",i,sum); 
    } /* Завершение параллельного фрагмента */ 
}
      
4.4. Пример динамического распределения итераций между потоками (использование параметра schedule директивы for)
4.3.2. Управление порядком выполнения вычислений

В результате распараллеливания цикла порядок выполнения итераций не фиксирован: в зависимости от состояния среды выполнения очередность выполнения итераций может меняться. Если же для ряда действий в цикле необходимо сохранить первичный порядок вычислений, который соответствует последовательному выполнению итераций в последовательной программе, то желаемого результата можно добиться при помощи директивы ordered (при этом для директивы for должен быть указан параметр ordered). Поясним сказанное на примере нашей учебной задачи. Для приведенного выше варианта программы печать сумм элементов строк матрицы будет происходить в некотором произвольном порядке; при необходимости печати по порядку расположения строк следует провести следующее изменение программного кода


 #pragma omp parallel for shared(a) \
 private(i,j,sum) schedule (dynamic, CHUNK)
 { 

  for (i=0; i < NMAX; i++) {
    sum = 0; 
    for (j=i; j < NMAX; j++) 
      sum += a[i][j]; 
    #pragma omp ordered
    printf ("Сумма строки %d равна %f\n",i,sum); 
    } /* Завершение параллельного фрагмента */ 
}
      
4.5. Пример использование директивы ordered

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

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

4.3.3. Синхронизация вычислений по окончании выполнения цикла

По умолчанию, все потоки, прежде чем перейти к выполнению дальнейших вычислений, ожидают окончания выполнения итераций цикла даже если некоторые из них уже завершили свои вычисления – конец цикла представляет собой некоторый барьер, который потоки могут преодолеть только все вместе. Можно отменить указанную синхронизацию, указав параметр nowait в директиве for – тогда потоки могут продолжить вычисления за переделами цикла, если для них нет итераций цикла для выполнения.

4.3.4. Введение условий при определении параллельных фрагментов (параметр if директивы parallel)

Теперь при наличии учебного примера можно пояснить назначение параметра if директивы parallel.

При разработке параллельных алгоритмов и программ важно понимать, что организация параллельных вычислений приводит к появлению некоторых дополнительных накладных затрат – в частности, в параллельной программе затрачивается время на создание потоков, их активизацию, приостановку при завершении параллельных фрагментов и т. п. Тем самым для достижения положительного эффекта сокращение времени вычислений за счет параллельного выполнения должно, по крайней мере, превышать временные затраты на организацию параллелизма. Для оценки целесообразности распараллеливания можно использовать параметр if директивы parallel, задавая с его помощью условие создания параллельного фрагмента (если условие параметра if не выполняется, блок директивы parallel выполняется как обычный последовательный код). Так, в нашем учебном примере можно ввести условие, определяющее минимальный размер матрицы, при котором осуществляется распараллеливание вычислений – программный код в этом случае может выглядеть следующим образом:

#include <omp.h>
#define NMAX 1000 
#define LIMIT 100
main () { 
 int i, j, sum; 
 float a[NMAX][NMAX]; 
 <инициализация данных>
 #pragma omp parallel for shared(a) \
 private(i,j,sum) if (NMAX>LIMIT)
 { 
  for (i=0; i < NMAX; i++) {
    sum = 0; 
    for (j=0; j < NMAX; j++) 
      sum += a[i][j]; 
    printf ("Сумма строки %d равна %f\n",i,sum); 
    } /* Завершение параллельного фрагмента */ 
}
      
4.6. Пример использования параметра if директивы parallel

4.4. Управление данными для параллельно-выполняемых потоков

Как уже отмечалось, потоки параллельной программы выполняются в общем адресном пространстве и, как результат, все данные (переменные) являются общедоступными для всех параллельно выполняемых потоков. Однако в ряде случаев необходимо наличие переменных, которые были бы локальными для потоков (например, для того, чтобы потоки не оказывали влияния друг на друга). И обратно – при одновременном доступе нескольких потоков к общим данным необходимо обеспечивать условия взаимоисключения (данный аспект организации доступа к общим данным будет рассмотрен в следующем разделе).

4.4.1. Определение общих и локальных переменных

Параметры shared и private директивы for для управления доступа к переменным уже использовались в примере 5.2. Параметр shared определяет переменные, которые будут общими для всех потоков. Параметр private указывает переменные, для которых в каждом потоке будут созданы локальные копии – они будут доступны только внутри каждого потока в отдельности (значения локальных переменных потока недоступны для других потоков). Параметры shared и private могут повторяться в одной и той же директиве несколько раз, имена переменных должны быть уже ранее определены и не могут повторяться в списках параметров shared и private. По умолчанию все переменные программы являются общими. Такое соглашение приводит к тому, что компилятор не может указать на ошибочные ситуации, когда программисты забывают описывать локальные переменные потоков в параметре private (отсутствие таких описаний приводит к тому, что переменные будут восприниматься как глобальные). Для выявления таких ошибок можно воспользоваться параметром default директивы parallel для изменения правила по умолчанию:

default ( shared | none )
      

При помощи этого параметра можно отменить действие правила по умолчанию (default(none)) или восстановить правило, что по умолчанию переменные программы являются общими (default(shared)).

Следует отметить, что начальные значения локальных переменных не определены, а конечные значения теряются при завершении потоков. Для их инициализации можно использовать параметр firstprivate директивы for, по которому начальные значения локальных переменных будут устанавливаться в значения, которые существовали в переменных до момента создания локальных копий. Запоминание конечных значений обеспечивается при помощи параметра lastprivate, в соответствии с которым значения локальных переменных копируются из потока, выполнившего последнюю итерацию. Поясним сказанное на примере рис. 4.5. На рисунке показана переменная sum, которая определена как lastprivate в директиве parallel for. Для этой переменной создаются локальные копии в каждом потоке, при завершении параллельного участка программного кода значение локальной переменной потока, выполнившего последнюю итерацию цикла, переписывается в исходную переменную sum.

Общая схема работы с локальными переменными потоков

Рис. 4.5. Общая схема работы с локальными переменными потоков
Дмитрий Остапенко
Дмитрий Остапенко

поддерживаю выше заданые вопросы

 

Павел Каширин
Павел Каширин

Скачал архив и незнаю как ничать изучать материал. Видео не воспроизводится (скачено очень много кодеков, различных плееров -- никакого эффекта. Максимум видно часть изображения без звука). При старте ReplayMeeting и Start в браузерах google chrome, ie возникает script error с невнятным описанием. В firefox ситуация еще интереснее. Выводится: 

Meet Now: Кукаева Светлана Александровна. 

Meeting Start Time: 09.10.2012, 16:58:04
Meeting Stop Time: 09.10.2012, 18:45:18
Recording Duration:01:47:14

Downloading...

Your Web browser is not configured to play Windows Media audio/video files.

Make sure the features are enabled and available.