Что мы можем сделать для эффективности, используя omp критический в ситуации, когда omp атомарный / сокращение не может быть применен? - PullRequest
0 голосов
/ 08 января 2019

Я столкнулся с одной проблемой в C ++.

Предположим, у нас есть vector<SomeClass> v, и мы хотим добавить все элементы v, используя многопоточность. (размер v равен N.) У нас есть перегрузка += оператора в SomeClass, но он не является атомно-совместимым.

SomeClass sum; // init by "zero" but not exactly a single (int)
#pragma omp parallel for
for (int i=0; i<N; ++i) {
   #pragma omp critical
   {
      sum += v[i];
   }
}

Мой эксперимент показывает, что время выполнения этого кода аналогично времени выполнения с одним потоком. Я думаю, что это связано с разделом critcial, где только одному потоку разрешено оценивать сложение одновременно. (Я не могу воспользоваться многопоточностью). Альтернативой может быть использование atomic или (reduction), но они недоступны, поскольку += не для атомарных переменных.

В таком случае, что мы можем сделать? Должен ли я выйти, чтобы использовать многопоточность здесь? Большое спасибо.

Ответы [ 2 ]

0 голосов
/ 12 января 2019

@ Ответ Брайса верен в том, что вы хотите сокращение, но для чего-то, где += - оператор, который вы хотите, вы должны иметь возможность использовать сокращение OpenMP изначально. Даже если это не так, спецификация предлагает определенные пользователем сокращения, чтобы разрешить сокращения для произвольных типов с произвольными выражениями, например:

// For a version that uses a `.combine()` method
// #pragma omp declare reduction(somered:SomeClass: omp_out.combine(omp_in))
#pragma omp declare reduction(somered:SomeClass: omp_out += omp_in)
// this assumes you can initialize with SomeClass tmp = 0;
// if not, add initializer() clause with a correct initialization for the tmp
SomeClass sum; // init by "zero" but not exactly a single (int)
#pragma omp parallel for reduction(somered: sum)
for (int i=0; i<N; ++i) {
      sum += v[i];
}
0 голосов
/ 10 января 2019

Вам нужно сделать сокращение. Если класс не поддерживается стандартной директивой reduction(op:var) openMP, вы можете использовать ее вручную.

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

SomeClass sum; // init by "zero" but not exactly a single (int)
#pragma omp parallel
{
    SomeClass mySum=0; //local accumulator, init with 0 or whatever the "zero" is for that class
    #pragma omp for
    for (int i=0; i<N; ++i) mySum += v[i];

    #pragma omp critical
    sum += mySum; //The critical section is entered only once
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...