ORDERED Directive
Назначение:
- Директива ORDERED устанавливает, что итерации вложенного цикла будут выполнены в таком же порядке, что и при последовательном выполнении
- Каждая нить перед выполнением своей порции итераций ждет завершения предыдущих порций.
- Используется в теле цикла for определенного как ORDERED
Формат:
#pragma omp for ordered [clauses...] (loop region) #pragma omp ordered newline structured_block (endo of loop region) |
Огранчения:
- Директива ORDERED может появляться только в контексте расширения директивы for/parallel for
- Только один поток может выполняться в секции ORDERED в момент времени
- Запрещается переход в блок или из блока ORDERED
- Итерация цикла не должна выполняться той же самой директивой ORDERED более чем один раз, и не должна выполняться более чем одна директива ORDERED
- Цикл, содержащий директиву ORDERED, должен быть определен клаузой ORDERED
Синхронизация типа ordered используется для определения потоков в параллельной области программы, которые выполняются в порядке, соответствующем последовательной версии программы.
Видно, что в приведенном примере вывод результатов элементов массива осуществляется в порядке возрастания индексов элементов массива, как в обычной последовательной программе.
void TestOrdered()
{
int a[20], i = 0;
#pragma omp parallel default(shared) private(i) num_threads(10)
{
#pragma omp for
for (i = 0; i < 20; i++)
a[i] = i * 2;
#pragma omp for ordered
for (i = 0; i < 20; i++)
{
a[i] = i + 8;//concurrent performing
#pragma omp ordered
printf_s("a[%d] = %d\n",i,a[i]);//serial, ordered performing
}
}
} Другой пример показывает различие в использовании директив ordered и critical.void TestOrdered()
{
int a[20], i = 0;
#pragma omp parallel default(shared) private(i) num_threads(10)
{
#pragma omp for
for (i = 0; i < 20; i++)
a[i] = i * 2;
#pragma omp for ordered
for (i = 0; i < 20; i++)
{
a[i] = i + 8;//concurrent performing
#pragma omp critical
printf_s("critical:a[%d] = %d\n",i,a[i]);
//not ordered performing
#pragma omp ordered
printf_s("\t\t\tordered: a[%d] = %d\n",i,a[i]);
//serial, ordered performing
}
}
}Применение директивы ordered может вызвать проблемы у начинающих программистов. Приведем пример кода:
Некорректно:
#pragma omp parallel for ordered for (int i = 0; i < 10; i++) { myFunc(i); } |
Корректно:
#pragma omp parallel for ordered for (int i = 0; i < 10; i++) { #pragma omp ordered { myFunc(i); } } |
Суть ошибки заключается в том, что в первом примере выражение ordered будет просто проигнорировано, поскольку не указана область его действия. Цикл будет выполняться в произвольном порядке.
Вторая особенность
Применение директивы диктуется зависимостью одной итерации от результата выполнения предыдущих итераций. Рассмотрим пример.
Некорректно:
int* arr = new int[10]; for(int i = 0; i < 10; i++) arr[i] = i; #pragma omp parallel for for (int i = 1; i < 10; i++) arr[i] = arr[i - 1]; for(int i = 0; i < 10; i++) printf("narr[%d] = %d", i, arr[i]); |
Теоретически эта программа должна вывести последовательность из нулей. Однако, на двухпроцессорной машине будет выведено некоторое количество нулей и некоторое количество пятерок (это связано с тем, что итерации как правило делятся между потоками пополам). Проблема легко решается с помощью директивы ordered.
Корректно:
int* arr = new int[10]; for(int i = 0; i < 10; i++) arr[i] = i; #pragma omp parallel for ordered for (int i = 1; i < 10; i++) { #pragma omp ordered arr[i] = arr[i - 1]; } for(int i = 0; i < 10; i++) printf("narr[%d] = %d", i, arr[i]); |
Дата добавления: 2015-02-03; просмотров: 976;