Директива для распределения итераций цикла между нитями:
C/C++:
#pragma omp for [ ключ [ ключ ] ... ] new-line
Цикл for
Fortran:
!$OMP DO [ ключ [ [ , ] ключ ] ... ]
Цикл DO
[ !$OMP END DO [ nowait ] ]
В Фортране директива END DO должна следовать непосредственно за строкой окончания оператора цикла DO. В языке Си директива применяется к блоку, находящемуся внутри оператора цикла for.
В список допустимых ключей входят все ключи директивы PARALLEL. Это позволяет объединять инструкции PARALLEL/END PARALLEL и DO/END DO в пару PARALLEL DO/END PARALLEL DO (parallel for в языках C/C++).
Помимо ключей общих с оператором PARALLEL, имеются ключи специфические для оператора for/DO:
SCHEDULE(тип[,m]) - указывает, каким образом итерации цикла будут распределены между нитями группы. В качестве параметра "тип" можно указать следующие значения:
STATIC - блочно-циклическое распределение итераций блоками размера m. Если m не определено, то размер блока определяется делением числа итераций на число нитей. Таким образом, каждой нити достается один блок. В случае, если число итераций не делиться нацело на число потоков, то компилятор сам распределит остаток между нитями.
DYNAMIC - динамическое распределение итераций с фиксированным размером блока m: сначала все нити получают порции из m итераций, а затем каждая нить, заканчивающая свою работу, получает следующую порцию из m итераций. По умолчанию m = 1.
GUIDED - динамическое распределение итераций блоками уменьшающегося размера; аналогично распределению DYNAMIC, но размер выделяемых блоков все время уменьшается, что в ряде случаев позволяет аккуратнее сбалансировать загрузку нитей. При управляемом планировании число итераций, выполняемых каждым потоком, определяется по следующей формуле:
число_выполняемых_потоком_итераций=Параметр m определяет минимальный размер блока. По умолчанию m = 1.
max(число_нераспределенных_итераций/число_нитей,m)
RUNTIME - способ распределения итераций цикла выбирается во время работы программы в зависимости от значения переменной OMP_SCHEDULE. Для этого типа распределения параметр m не задается.
AUTO - способ распределения итераций выбирается компилятором или средой исполнения. Параметр m не задается.
LASTPRIVATE (список) - список переменных, которые по окончании параллельного блока должны быть сохранены в базовых переменных. Сохраняются значения с последнего шага цикла.
ORDERED - позволяет задавать внутри тела цикла директивы ORDERED, которые упорядочивают последовательность выполнения шагов цикла.
COLLAPSE(n) - Указывает, сколько вложенных циклов должны образовать единое пространство итераций, которое делится между нитями в соответствии с ключом SCHEDULE.
NOWAIT - директива отменяет необходимость барьерной синхронизации нитей в конце параллельного цикла.
Пример программы с распределением итераций цикла между нитями:
Программа for.c
#include <stdio.h> #include <stdlib.h> #define TRUE 1 int main() { int i, n = 18; omp_set_num_threads(4); /* Функция omp_set_num_threads задает число нитей в параллельном регионе */ #pragma omp parallel default(none) shared(n) private(i) { #pragma omp for schedule(static) for (i=0; i<n; i++) printf("Нить %d исполняет %d итерацию\n", omp_get_thread_num(),i); /* Функция omp_get_thread_num() определяет номер вызвавшей ее нити */ } return 0; }
Программа do.f
program do integer i,n,TID, omp_get_thread_num n = 18 call omp_set_num_threads(4) C Функция omp_set_num_threads задает число нитей в C параллельном регионе !$OMP PARALLEL default(none) shared(n) private(i,TID) !$OMP DO schedule(static) do i = 1, n TID = omp_get_thread_num() C Функция omp_get_thread_num() определяет номер C вызвавшей ее нити. print *, 'Thread = ', TID, ' doing', i, 'iteration' end do !$OMP END DO !$OMP END PARALLEL End