При вычислении максимального сокращения внутри параллельного цикла 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?
}
}
Это максимум только для определенного потока или это максимум всех потоков?
Это частное значение «на поток» в параллельной области 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;
}
Значение редукционной переменной не определено в конструкции, которая использует reduction
близко и отличается среди потоков. Для каждого потока есть личные копии переменной. Вам придется пересмотреть свое распараллеливание.
Из спецификаций OpenMP 4:
Для параллельных и разделяющих конструкций, частная копия каждого списка
элемент создан, один для каждой неявной задачи, как если бы частное предложение
был использован. … Личная копия затем инициализируется как указано
выше. В конце региона, для которого оговорка о сокращении была
указанный исходный элемент списка обновляется путем объединения его исходного
значение с окончательным значением каждой из частных копий, используя
объединитель указанного редукционного идентификатора.
Другие ответы ясно дали понять, что максимальное сокращение openmp не обеспечивает необходимую мне функциональность. Поэтому я нашел другой способ реализовать его с помощью атомарной операции 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(¤tmax,randomarray[i]);
output[i]=randomarray[i]/currentmax; //max among all threads
}
}