Каково использование сокращения в openmp?

У меня есть этот кусок кода, который распараллелен.

int i,n; double area,pi,x;
area=0.0;
#pragma omp parallel for private(x) reduction (+:area)
for(i=0; i<n; i++){
x= (i+0.5)/n;
area+= 4.0/(1.0+x*x);
}
pi = area/n;

Говорят, что сокращение устранит состояние гонки, которое могло бы произойти, если бы мы не использовали сокращение. Тем не менее мне интересно, нужно ли нам добавлять lastprivate для области, поскольку она используется вне параллельного цикла и не будет видна за его пределами. В противном случае скидка распространяется и на это?


person MadHatter    schedule 13.05.2013    source источник
comment
Вы не хотите использовать последний приват. Прочитайте эту ссылку, чтобы узнать о сокращениях, firstprivate, lastprivate и других вещах в OpenMP bisqwit. iki.fi/story/howto/openmp/#ReductionClause. Смотрите мой ответ для получения дополнительной информации о скидках.   -  person    schedule 15.05.2013


Ответы (2)


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

thread 1 - private area = compute(x)
thread 2 - private area = compute(y)
thread 3 - private area = compute(z)

reduction step - public area = area<thread1> + area<thread2> + area<thread3> ...
person SNce    schedule 13.05.2013
comment
Спасибо. Значит, пи получает правильное значение, а не 0? Я думал, что значения, определенные за пределами параллельных разделов, потеряют значение вне цикла, если они не определены как lastprivate. - person MadHatter; 14.05.2013

Вам не нужен lastprivate. Чтобы помочь вам понять, как выполняются редукции, я думаю, будет полезно посмотреть, как это можно сделать с помощью atomic. Следующий код

float sum = 0.0f;
pragma omp parallel for reduction (+:sum)
for(int i=0; i<N; i++) {
    sum += //
}

эквивалентно

float sum = 0.0f;
#pragma omp parallel
{
    float sum_private = 0.0f;
    #pragma omp for nowait
    for(int i=0; i<N; i++) {
        sum_private += //
    }
    #pragma omp atomic
    sum += sum_private;
}

Хотя этот вариант содержит больше кода, полезно показать, как использовать более сложные операторы. Одним из ограничений при подаче иска на reduction является то, что atomic поддерживает только несколько основных операторов. Если вы хотите использовать более сложный оператор (например, добавление SSE/AVX), вы можете заменить atomic на critical уменьшение с OpenMP с SSE/AVX

person Community    schedule 14.05.2013