Почему в OpenMP запрещен оператор! =?

Я пытался скомпилировать следующий код:

#pragma omp parallel shared (j)
{
   #pragma omp for schedule(dynamic)
   for(i = 0; i != j; i++)
   {
    // do something
   }
}

Я получаю эту ошибку: ошибка: неверный контроль предиката.

Я проверяю справочное руководство openMP , и он говорит, что для параллелизма для него "только" допускает один из следующих операторов: < <= → =.

Я не понимаю, почему не разрешить i != j. Я мог понять, было ли это статическим расписанием, поскольку openMP необходимо предварительно вычислить количество итераций, назначенных каждому потоку. Но я не могу понять, почему это ограничение в таком случае, например. Любые подсказки?


EDIT: даже если я делаю for(i = 0; i != 100; i++), хотя я мог бы просто поставить "<" или "< =".

Ответ 1

.

Я отправил электронное письмо разработчикам OpenMP по этому вопросу, ответ, который я получил:

Для подписанного int поведение обертки undefined. Если мы допустим !=, программисты могут получить неожиданный откат. Проблема заключается в том, может ли компилятор генерировать код для вычисления количества попыток для цикла.

Для простого цикла, например:

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

компилятор может определить, что существуют "n" итерации, , если n >= 0, и нулевые итерации , если n < 0.

Для цикла, подобного:

for( i = 0; i != n; ++i ) 

снова, компилятор должен уметь определять, что существуют "n" итерации, , если n >= 0; , если n < 0, мы не знаем, сколько итераций оно имеет.

Для цикла, подобного:

for( i = 0; i < n; i += 2 )

компилятор может генерировать код для вычисления подсчета отключения (счетчик циклов) как floor ((n + 1)/2), если n >= 0 и 0 , если n < lt; 0.

Для цикла, подобного:

for( i = 0; i != n; i += 2 )

компилятор не может определить, "i" когда-либо ударит "n" . Что, если "n" - нечетное число?

Для цикла, подобного:

for( i = 0; i < n; i += k )

компилятор может генерировать код для вычисления подсчета отключения как floor ((n + k-1)/k), если n >= 0 и 0 , если n < 0, потому что компилятор знает, что цикл должен подсчитываться; в этом случае, если k < 0, это не законная программа OpenMP.

Для цикла, подобного:

for( i = 0; i != n; i += k )

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

Кредиты: OpenMP ARB

Ответ 2

В отличие от того, как это может выглядеть, schedule(dynamic) не работает с динамическим числом элементов. Скорее назначение итерационных блоков для потоков - это динамическое. При статическом планировании это назначение предварительно вычисляется в начале конструкции workharing. При динамическом планировании итерационные блоки выдаются потокам на основе первого, первого обслуживания.

В стандарте OpenMP довольно ясно, что количество итераторов предварительно вычисляется после того, как встречается конструктор workhare, поэтому счетчик циклов не может быть изменен внутри тела цикла (спецификация OpenMP 3.1, §2.5.1 - Loop Construct)

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

Целый тип (или вид для Fortran), используемый для вычисления количества итераций для свернутый цикл определяется реализацией.

В цикле обработки кадров имеются логические итерации с нумерацией 0,1,..., N-1, где N - число итерации цикла, а логическая нумерация обозначает последовательность, в которой итерации будет выполняться, если связанный цикл был выполнен одним потоком. schedule указывает, как итерации связанных циклов делятся на смежные непустые подмножества, называемые кусками, и как распределяются эти куски среди нитей команды. Каждый поток выполняет назначенный блок в контексте его неявной задачей. Выражение chunk_size оценивается с использованием исходных элементов списка любых переменных, которые сделаны private в контуре цикла. Неясно, в каком порядке или сколько раз возникают побочные эффекты оценки этого выражения. Использование переменной в выражении предложения schedule конструкции цикла вызывает неявное обращение к переменной во всех вложенных конструкциях.

Обоснование этих ограничений реляционного оператора довольно простое - оно дает четкое указание на то, что является направлением цикла, оно легко вычисляет количество итераций и обеспечивает аналогичную семантику директивы OpenMP forharing в C/С++ и Fortran. Кроме того, другим реляционным операциям потребуется тщательный осмотр тела цикла, чтобы понять, как проходит цикл, который во многих случаях был бы неприемлем и сделает выполнение громоздким.

OpenMP 3.0 представил явную конструкцию task, которая позволяет распараллеливать циклы с неизвестным числом итераций. Однако есть уловка: задачи вносят некоторые серьезные накладные расходы, и одна задача для каждой итерации цикла имеет смысл, если эти итерации занимают довольно много времени для выполнения. В противном случае служебные данные будут доминировать над временем выполнения.

Ответ 3

Ответ прост. OpenMP не допускает преждевременного завершения команды потоков. С == или! =, OpenMP не может определить, когда цикл остановится. 1. Один или несколько потоков могут попасть в условие завершения, которое может быть не уникальным. 2. OpenMP не имеет возможности отключить другие потоки, которые никогда не смогут обнаружить условие.

Ответ 4

Если бы я увидел утверждение

for(i = 0; i != j; i++)

используется вместо утверждения

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

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

Здесь код, который вызывает проблемы при использовании != и может помочь объяснить, почему это не разрешено.

#include <cstdio>

int main(){
    int j=10;
   #pragma omp parallel for
   for(int i = 0; i < j; i++){
    printf("%d\n",i++);
   }
}

обратите внимание, что i увеличивается как в выражении for, так и в самом цикле, что приводит к возможности (но не гарантии) бесконечного цикла.

Если предикат <, тогда поведение цикла может быть хорошо определено в параллельном контексте, если компилятор не должен проверять внутри цикла изменения на i и определять, как эти изменения влияют на границы цикла.

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

Ответ 5

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

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