OPENMP Iteriation никогда не выходит - PullRequest
1 голос
/ 03 декабря 2011

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

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

#include <stdio.h>
#include <omp.h>
int main(int argc, char **argv)
{
    float error = 20;
#pragma omp parallel shared(error)
    {
        while (error > 5)
        {
#pragma omp for  reduction(-:error)
            for (int i=0; i<10; ++i)
            {
                error -= 1;
            }
        }

    }
    fprintf(stderr, "Program terminated\n");
    return 0;
}

Ответы [ 2 ]

1 голос
/ 03 декабря 2011

это маленькая забавная проблема.У меня нет впечатляющего опыта работы с openmp, но после некоторых экспериментов с вашим кодом, я думаю, что проблема вызвана отсутствием синхронизации при входе в параллель для цикла for (вставьте оператор записи для «просмотра» вашего кода).

Выможно заставить код работать, вставив барьер непосредственно перед параллельным циклом for:

#pragma omp barrier
#pragma omp for reduction(-:error)
   for(int i=0; i<10; ++i)

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

0 голосов
/ 18 ноября 2018

Ваша программа имеет неопределенное поведение .См. Раздел 2.8 в спецификации OpenMP 5.0 1 :

Каждая область общего доступа должна встречаться всеми потоками в команде или вообще ни с кем

Это означает, что любой вид ветви (if, while и т. Д.) , чье состояние может быть различным для разных потоков вокруг #pragma omp for (или любого другого worksharing construct ) недопустим:

#pragma omp parallel
{
  if (...true for some threads, false for others...) // ILLEGAL!
  {
    #pragma omp for
    for (...) ...
  }

  while (...true for some threads, false for others...) // ILLEGAL!
  {
    #pragma omp for
    for (...) ...
  }
}

В вашем случае это неопределенное поведение, вероятно, приводит к следующей последовательности событий:

  • Каждый поток проверяетусловие, но оно может быть не одинаковым для всех потоков - некоторые входят в цикл while, некоторые - нет.
  • Если они входят в цикл while:
    • Они сталкиваются#pragma omp for.
    • В цикле for они обновляют error.
    • Они ждут у неявного барьера в конце #pragma omp for.
  • Если они не входят в цикл while:
    • Они ждут у неявного барьера в конце #pragma omp parallel.

Когда поток OpenMP достигает барьера, он ожидает, пока все потоки в его команде не достигнут барьера. Неявный барьер #pragma omp for не адаптируется к числу потоков, с которыми столкнулась конструкция. В вашем случае некоторые потоки никогда не достигнут барьера в конце цикла for (потому что для нихусловие while было ложным).Они пропустили цикл while и теперь ждут у неявного барьера в конце #pragma omp parallel.

В результате возникает тупик: некоторые потоки ждут в конце #pragma omp for, другие - вконец #pragma omp parallel, и две группы больше никогда не соберутся вместе ...


Явный барьер перед #pragma omp for, предложенный в ответе Уолтера, исправляет это, разделяя чтение и запись общей переменнойerror.Более конкретно:

  • Каждый поток проверяет условие, и оно одинаково для всех - либо все, либо ни один не входят в тело цикла while.
  • Если они входят в while loop:
    • Все они ждут у явного барьера.
    • Все они сталкиваются с #pragma omp for.
    • В цикле for они обновляют error.
    • Все они ждут у неявного барьера в конце #pragma omp for.(Барьер подразумевает неявное flush, что означает, что все потоки видят окончательное значение error.)
    • Вернитесь к началу.
  • Послеwhile loop:
    • Все они ждут у неявного барьера в конце #pragma omp parallel.
    • Готово.

ИзКонечно, теперь все потоки выполняют цикл for, и это не «минимизирует издержки распараллеливания», что вам и нужно.Я думаю, вам придется еще немного реструктурировать свой код, чтобы достичь этой цели.Может быть, использование #pragma omp task вместо #pragma omp for может быть хорошим подходом, но это зависит от деталей ваших реальных структур данных и алгоритмов.


Примечание: вы можете получитьизбавиться от тупика, добавив предложение nowait к #pragma omp for, но это было бы хаком, и ваша программа все равно имела бы неуказанное поведение .


1: ... или соответствующий раздел в других версиях OpenMP.

...