С++ openmp для максимального значения уменьшения цикла во время выполнения цикла

При вычислении максимального сокращения внутри параллельного цикла for каково значение переменной максимального сокращения в промежуточные моменты времени во время выполнения цикла? Это максимум только для определенного потока или это максимум всех потоков?

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

Например:

#include <stdio.h>
#include <omp.h>

int main(int argc, char *argv[]) {

    double randomarray[10];
    //initialize the random array

    double outputarray[10];
    double currentmax = 0;

    #pragma omp parallel for reduction(max:currentmax)
    for( i=0;i<10; i++) {

        if(randomarray[i] > currentmax)
        {
            currentmax = randomarray[i];   
        }

        output[i]=randomarray[i]/currentmax;
        // is this current max for the currently 
        // executing thread or all threads?
    }

}

person zimzam    schedule 30.10.2014    source источник
comment
Ваш текущий код слишком прост и ограничен пропускной способностью памяти.   -  person Z boson    schedule 05.11.2014
comment
@Zboson У меня есть конкретная проблема, которую я пытаюсь решить, где мне нужно знать текущий максимум до того, как будет вычислен глобальный максимум; поэтому ваше предложение сделать два прохода не имеет ничего общего с проблемой, которую я пытаюсь решить. Если вы знаете лучшее решение, которое не ограничивает пропускную способность памяти, поделитесь им.   -  person zimzam    schedule 07.11.2014


Ответы (3)


Это максимум только для определенного потока или это максимум всех потоков?

Это частное значение «для каждого потока» в параллельной области OpenMP.

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

#pragma omp parallel for
for( i=0;i<10; i++) {
  double local_max;

  #pragma omp critical
  {
    if(randomarray[i] > currentmax)
    {
      currentmax = randomarray[i];   
    }
    local_max = currentmax;
  }

  output[i]=randomarray[i]/local_max;
}
person yohjp    schedule 02.11.2014

Значение переменной сокращения не определено в конструкции, использующей reduction close, и отличается в разных потоках. Для каждого потока существуют частные копии переменной. Вам придется переосмыслить распараллеливание.

Из спецификаций OpenMP 4:

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

person Vladimir F    schedule 01.11.2014

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

inline double __sync_fetch_and_max_double(double* address, double val) {
  int64_t* address_as_int64 = (int64_t*)address;
  int64_t old = *address_as_int64, assumed;
  do {
    assumed = old;
    double assumed_double = *((double*)&assumed);
    double min = (val > assumed_double) ? val : assumed_double;
    old = __sync_val_compare_and_swap(address_as_int64, assumed,
                                      *((int64_t*)&min));
  } while (assumed != old);
  return *((double *)&old);
}

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

Модифицированный код выглядит так:

#include <stdio.h>
#include <omp.h>

int main(int argc, char *argv[]) {

    double randomarray[10];
    //initialize the random array

    double outputarray[10];
    double currentmax = 0;

    #pragma omp parallel for
    for( i=0;i<10; i++) {

        __sync_fetch_and_max_double(&currentmax,randomarray[i]);   

        output[i]=randomarray[i]/currentmax; //max among all threads

    }

}
person zimzam    schedule 04.11.2014
comment
Есть много различных способов сделать это. Например. вам не нужно использовать атомарный или критический. Вы можете сделать первый проход, чтобы найти максимальное значение для каждого потока, а затем передать значения каждому потоку для исправления, а затем выполнить второй проход. Это то, что я делаю с суммой префикса. Но то, что вы сейчас делаете, в любом случае связано с пропускной способностью памяти (как и сумма префиксов), так что это не очень интересно. Чего вы в конечном итоге пытаетесь достичь? - person Z boson; 05.11.2014