Сокращение с помощью OpenMP

Я пытаюсь вычислить среднее значение 2-мерной матрицы, используя openmp. Эта 2d матрица на самом деле является изображением.

Я делаю поточное разделение данных. Например, если у меня N потоков, то я обрабатываю количество строк /N строк с помощью thread0 и так далее.

У меня такой вопрос: могу ли я использовать условие сокращения openmp с " #pragma omp parallel "?

#pragma omp parallel reduction( + : sum )
{
    if( thread == 0 )
       bla bla code 
       sum = sum + val;

    else if( thread == 1 )
       bla bla code
       sum = sum + val;
}

Ответ 1

Да, вы можете - предложение сокращения применимо ко всей параллельной области, а также к индивидуальным конструкциям обхода for. Это позволяет, например, сокращение по сравнению с вычислениями, выполненными в разных параллельных сечениях (предпочтительный способ реструктурирования кода):

#pragma omp parallel sections private(val) reduction(+:sum)
{
   #pragma omp section
   {
      bla bla code
      sum += val;
   }
   #pragma omp section
   {
      bla bla code
      sum += val;
   }
}

Вы также можете использовать конструкцию OpenMP for workharing для автоматического распределения итераций цикла между потоками в команде, а не переопределять ее с помощью разделов:

#pragma omp parallel for private(val) reduction(+:sum)
for (row = 0; row < Rows; row++)
{
   bla bla code
   sum += val;
}

Обратите внимание, что редукционные переменные являются частными и их промежуточные значения (т.е. значение, которое они удерживают до сокращения в конце области parallel), являются лишь частичными и не очень полезными. Например, следующий последовательный цикл не может быть (легко?) Преобразован в параллельный с восстановлением:

for (row = 0; row < Rows; row++)
{
   bla bla code
   sum += val;
   if (sum > threshold)
      yada yada code
}

Здесь yada yada code должен выполняться на каждой итерации, как только накопленное значение sum прошло значение threshold. Когда цикл выполняется параллельно, частные значения sum могут никогда не достигнуть threshold, даже если их сумма будет выполнена.

Ответ 2

В вашем случае sum = sum + val может интерпретироваться как val[i] = val[i-1] + val[i] в массиве 1-d (или val[rows][cols] = val[rows][cols-1] + val[rows][cols] в 2-мерном массиве), который является префикс суммы.

Сокращение является одним из решений для суммы префикса, вы можете использовать сокращение для любых коммутативно-ассоциативных операторов, таких как '+', '-', '*', '/'.