Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

LEC02

.pdf
Скачиваний:
15
Добавлен:
14.04.2015
Размер:
237.57 Кб
Скачать

#pragma omp for: конфликты (2)

Если в теле цикла потоки меняют значение общей переменной, то возможно искажение данных в этой переменной при одновременной попытке записи.

Ответственность за обнаружение таких конфликтов лежит на программисте. OpenMP не обнаружит конфликт и скомпилирует следующую ошибочную программу:

s = 0;

#pragma omp parallel for num_threads(2) shared(a, s) private(i) for (i = 0; i < 20; i++) {

a[i] = i;

s = s + a[i] ;

}

Массив a заполнится корректно, однако его сумма s будет рассчитана ошибочно, если на какой-либо из итераций поток 0 и поток 1 попытаются модифицировать s одновременно.

21

Защита общих переменных

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

s= 0;

#pragma omp parallel for num_threads(2) shared(a, s) private(i) for(i = 0; i < 20; i++) {

a[i] = i;

#pragma omp critical s = s + a[i] ;

}

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

22

#pragma omp atomic

Защита операции присвоения общих переменных возможна также с помощью более быстрой директивы atomic, которую можно использовать только для атомарных аппаратноускоряемых команд вида «load-modify-store», имеющих вид:

x <операция>= <выражение>;

где <операция> может быть +, , −, /, &, ˆ, |, <<, >> ;

x++;

++x ;

x−− ;

−− x ;

Примеры:

#pragma omp atomic Counter += 10; #pragma omp atomic

Counter += a++; // ошибка: операция a++ не будет защищена 23

Параметр reduction

Если в теле цикла потоки меняют значение общей переменной, просто накапливая сумму, то возможно более эффективное устранение конфликта:

#pragma omp parallel for num_threads(2) shared(a, s) private(i) reduction(+:s) for(i = 0; i < 20; i++) {

a[i] = i;

s = s + a[i] ;

}

В результате s будет подсчитано корректно, при этом операция модификации s будет выполняться потоками параллельно (одновременно), т.к. OpenMP создаст локальные копии s для каждого потока. По окончании цикла OpenMP сложит все локальные копии и поместит их в общую переменную s.

Помимо операции +, параметр reduction умеет работать с другими операциями: -, *, /

OpenMP самостоятельно инициализирует локальные переменные s значением 0 или 1 (в зависимости от операции), игнорируя начальное значение переменной s.

24

Проблема балансировки нагрузки

25

#pragma omp for schedule

#pragma omp for schedule(static, chunk_size)

#pragma omp for schedule(dynamic,chunk_size)

#pragma omp for schedule(guided, chunk_size)

#pragma omp for schedule(runtime)

(runtime подставляется из переменной среды окружения OMP_SCHEDULE)

#pragma omp parallel num_threads(8)

{

#pragma omp for schedule(dynamic,1) for (i = 0; i < 8; i++)

printf("[1] iter %d, tid %d\n", i, omp_get_thread_num()); #pragma omp for schedule(static,1)

for (i = 0; i < 8; i++)

printf("[2] iter %d, tid %d\n", i, omp_get_thread_num());

}

26