OpenMP: 2 вложенных цикла For для цикла while.Как исправить многопоточный функционал?(Якоби Солвер) - PullRequest
0 голосов
/ 05 мая 2019

Я пытаюсь распараллелить решатель Якоби, используя OpenMP.

Когда используется 1 поток:

В нынешнем виде код выполняется правильно, когда назначен только один поток,и выдает те же результаты, что и эталонная однопотоковая функция (не показана).
Цикл while прерывается, когда разностная переменная меньше 0,01000 (как и должно быть)

Когда два или более потоковиспользуются:

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

Я протестировал множество итераций компиляции для стратегического размещения соответствующих переменных в разделах shared / private / reduction, надеясь получить значение diff для правильного накопления во всех используемых потоках.Я понял, что переменная "diff" должна использоваться всеми потоками, но то, что я пробовал, не сработало для накопления значений из всех потоков.Я не уверен, что еще я могу попробовать?

Спасибо за ваше время и ввод

int 
compute_using_omp_jacobi (grid_t *grid, int num_threads)
    {

/////////////////////////////////////////////////////////
  int i, j;
  int num_iter = 0;
    int done = 0;

    double diff;
    float old, new; 
  float eps = 1e-2; /* Convergence criteria. */
  int num_elements; 


omp_set_num_threads(num_threads);

#pragma omp parallel default(none) shared(grid, eps, done, diff) private ( i, j, old, new, num_elements) reduction (+:num_iter)




    while(!done) { /* While we have not converged yet. */
    diff = 0.0;
  num_elements = 0;

#pragma omp for reduction (+: diff) collapse(2)
        for (i = 1; i < (grid->dim - 1); i++) 

            for (j = 1; j < (grid->dim - 1); j++) {
                old = grid->element[i * grid->dim + j]; /* Store old value of grid point. */
                /* Apply the update rule. */    
                new = 0.25 * (grid->element[(i - 1) * grid->dim + j] +\
                              grid->element[(i + 1) * grid->dim + j] +\
                              grid->element[i * grid->dim + (j + 1)] +\
                              grid->element[i * grid->dim + (j - 1)]);

                grid->element[i * grid->dim + j] = new; /* Update the grid-point value. */
                diff = diff + fabs(new - old); /* Calculate the difference in values. */
                num_elements++;
                 //printf ("DIFF %f.", diff);
            }


        /* End of an iteration. Check for convergence. */
        diff = diff/num_elements;
        printf ("Iteration %d. DIFF: %f.\n", num_iter, diff);
//        printf ("number of elements %d.", num_elements);


        num_iter++;

        if (diff < eps) 
            done = 1;
    }

    return num_iter;
}

1 Ответ

1 голос
/ 06 мая 2019

Нельзя распараллелить цикл while, поскольку значения grid->element в каждой итерации зависят от значений из предыдущей итерации.

Вам придется переместить #pragma omp parallel в то время как (до первого цикла for).

num_elements должен быть назван в предложении reduction, а new и old должны быть объявлены в теле внутреннего цикла for.

...