Гоночные условия с OpenMP - PullRequest
       14

Гоночные условия с OpenMP

1 голос
/ 25 января 2012

Мне нужно заполнить 2D массив (tmp[Ny][Nx]), в то время как каждая ячейка массива получает интеграл (некоторой функции) как функцию от свободных параметров.Поскольку я имею дело с очень большими массивами (здесь я упростил мой случай), мне нужно использовать OpenMP параллелизм, чтобы ускорить мои вычисления.Здесь я использую простую директиву #pragma omp parallel for.

Без использования #pragma omp parallel for код выполняется идеально.Но добавление параллельной директивы приводит к появлению условий гонки в выходных данных.

Я попытался вылечить это, сделав private(i,j,par), это не помогло.

PS Я использую VS2008 Professional с OpenMP 2.0 и под ОС Windows 7

Вот мой код: (краткий пример)

testfunc(const double* var, const double* par)
{
    // here is some simple function to be integrated over
    // var[0] and var[1] and two free parameters par[0] and par[1]
    return ....
}

#define Nx 10000
#define Ny 10000
static double tmp[Ny][Nx];

int main()
{    
    double par[2]; // parameters
    double xmin[]={0,0} // limits of 2D integration
    double xmax[]={1,1};// limits of 2D integration

    double val,Tol=1e-7,AbsTol=1e-7;
    int i,j,NDim=2,NEval=1e5;

#pragma omp parallel for private(i,j,par,val) 
    for (i=0;i<Nx;i++)
    {
        for (j=0;j<Ny;j++)
        {
            par[0]=i;
            par[1]=j*j;
            adapt_integrate(testfunc,par, NDim, xmin, xmax,
                            NEval, Tol, AbsTol, &val, &err);
            // adapt_integrate - receives my integrand, performs
            // integration and returns a result through "val"
            tmp[i][j] = val;
        }
    }
}  

Он генерирует условия гонки навыход.Я попытался избежать этого, сделав все внутренние переменные (i, j, par и val) закрытыми, но это не помогло.

PS Последовательная версия (# threads = 1) этого кода работает правильно.

1 Ответ

0 голосов
/ 31 января 2015

(Ответ на вопрос. Преобразован в вики-ответ сообщества. См. Вопрос без ответов, но проблема решена в комментариях (или расширена в чате) )

ОП написал:

Решенная проблема!

Я определил параметры интеграции как глобальные и использовал для них директиву #pragma omp threadprivate(parGlob).Теперь это работает как шарм.Я думал, что private() и threadprivate() имеют одно и то же значение, просто разные способы реализации, но они этого не делают.

Таким образом, игра с этими директивами может дать правильный ответ.Другое дело, что определение итератора i внутри первого цикла for дает дополнительное увеличение производительности на 20-30%.Итак, самая быстрая версия кода теперь выглядит так:

testfunc(const double* var, const double* par)
    {
       .......
    }

    #define Nx 10000
    #define Ny 10000
    static double tmp[Ny][Nx];
    double parGlob[2]; //<- Here are they!!!
    #pragma omp threadprivate(parGlob)  // <-Magic directive!!!!

    int main()
    {    
 // Not here !!!! ->       double par[2]; // parameters
        double xmin[]={0,0} // limits of 2D integration
        double xmax[]={1,1};// limits of 2D integration

        double val,Tol=1e-7,AbsTol=1e-7;
        int j,NDim=2,NEval=1e5;

    #pragma omp parallel for private(j,val)  // no `i` inside `private` clause
        for (int i=0;i<Nx;i++)
        {
            for (j=0;j<Ny;j++)
            {
                parGlob[0]=i;
                parGlob[1]=j*j;
                adapt_integrate(testfunc,par, NDim, xmin, xmax,
                                NEval, Tol, AbsTol, &val, &err);
                tmp[i][j] = val;
            }
        }
    }  
...