OpenMP l oop каждый раз дает другой результат - PullRequest
1 голос
/ 12 января 2020
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <omp.h>
#define KE 10
#define NSTEPS 100
main()
{
    float ex[KE],hy[KE];
    float bn[NSTEPS];
    int n,k,kc,ke;
    float ddx,dt,T;
    float t0,spread,pulse;
    omp_set_num_threads(4);
    kc = KE/2;
    t0 = 40.0;
    spread = 12;
    T = 0;
    FILE * temp = fopen("Exserial.txt", "w");
    /* Initialize */
    for ( k=0; k <= KE; k++ )
    {
        ex[k] = 0.0;
        hy[k] = 0.0;
    }
    double strt=omp_get_wtime();
#pragma omp parallel shared(ex,hy,bn) private(n,k,T,pulse,t0,spread)
    {
        for ( n=1; n<=NSTEPS ; n++) {
            T = T + 1;
            pulse = exp(-.5*(pow( (t0-T)/spread,2.0) ));
            ex[kc] = pulse;
    /* Main FDTD Loop */
    /* Calculate the Ex field */
#pragma omp critical
            {
#pragma omp for 
                for ( k=1; k < KE; k++ )
                { 
#pragma omp atomic update
                    ex[k] = ex[k] + .5*( hy[k-1] - hy[k] ) ;
                    bn[n]=ex[100];
                }
    /* Calculate the Hy field */
#pragma omp for
                for ( k=0; k < KE-1; k++ )
                {
#pragma omp atomic update
                    hy[k] = hy[k] + .5*( ex[k] - ex[k+1] ) ;
                }
            }
        }
    }
    double end=omp_get_wtime();
    printf( "------------------%f\n",end-strt);
    /* End of the Main FDTD Loop */
    /* At the end of the calculation, print out the Ex and Hy fields */
    for ( k=1; k <=KE; k++ )
    { 
        fprintf(temp, "%f\n",ex[k]);
        printf( "%f\n",ex[k]);
    }
}

параллельный выход (используется число потоков = 4)

 ------------------0.013850
    0.030408
    -0.130364
    0.107690
    0.061082
    0.023526
    0.066983
    -0.030821
    -0.024117
    0.037548
    0.000000

последовательный выход

-0.013813
-0.028405
-0.044722
-0.064258
-0.087550
-0.072226
-0.062273
-0.055638
-0.052620
0.000000

Я не знаю, где я ошибаюсь, но получаю разные результаты в параллельной программе. Это дает разные результаты каждый раз. есть еще одна проблема, т.е. когда я удаляю #pragma omp parallel сверху, я получаю правильное значение, но никаких временных преимуществ. Я должен добавить #pragma omp parallel, поэтому нужно какое-то решение.

1 Ответ

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

Как подсказывает @ 1201ProgramAlarm, у вас есть гонка данных. Он включает этот оператор внутри параллельной области и вне критической секции:

            ex[kc] = pulse;

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

Но проблемы здесь настолько велики, что гонка данных в значительной степени несущественна. Проблема main состоит в том, что вычисления имеют сильные зависимости данных между l oop итерациями. То есть при последовательном запуске каждая итерация внешнего l oop обновляет все элементы ex и hy на основе значений, вычисленных в предыдущей итерации. Независимо от того, сколько вы синхронизируете или насколько важна критическая причина, вы не сможете ожидать тех же результатов (или даже последовательных результатов), если разрешите выполнение итераций external-l oop в другом порядке, например, в качестве распараллеливания. делает.

Серебряная подкладка в том, что распараллеливание в любом случае не принесло вам большой пользы, потому что почти вся работа, выполняемая внешним l oop, находится в критической секции. Простое удаление директив omp parallel и omp critical может go значительно улучшить этот код. Для таких маленьких KE и таких простых вычислений, вероятно, также не имеет смысла оставлять внутренние omp for s, но если бы KE был намного больше, вы могли бы оставить распараллеливание внутренних циклов.

...