Вызов функции внутри цикла OpenMP для

0

Просто начинайте работу с OpenMP. Мне было интересно, можно ли запустить OpenMP-параллель в цикле for, который вызывает внешнюю функцию, которая сама по себе не вызывает никакой другой функции. Я поставил некоторый упрощенный код, чтобы понять:

#pragma omp parallel for
for(span=0;span<info.nospanelement;span++)
{
    some_function(info,wakePtr[time][span],P,w_ind,1);

    //additions to be done each repeat
    w_wake[0] += w_ind[0];
    w_wake[1] += w_ind[1];
    w_wake[2] += w_ind[2];
}

Я знаю, что мне нужно добавить еще немного для вызова, но может ли этот цикл OpenMp технически работать?

  • 1
    "а я получаю некоторые ошибки" какие ошибки?
Теги:
multithreading
openmp

1 ответ

2
Лучший ответ

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

В вашей программе несколько потоков читают одно и то же значение переменной, затем каждый добавляет к ней другое значение, затем все они записывают результат в том же месте, так что многие вычисления переписываются и не суммируются до окончательного результат. Из-за этого результаты, рассчитанные вашей программой, ниже, чем правильные значения (кстати, вы должны точно указать, как результат вашей программы отличается от того, что вы ожидали).

Простым, но неэффективным обходным путем является использование атомных добавок:

#pragma omp parallel for
    for(span=0;span<info.nospanelement;span++) {
        some_function(info,wakePtr[time][span],P,w_ind,1);

        //additions to be done each repeat
#pragma omp atomic
    w_wake[0] += w_ind[0];
#pragma omp atomic
    w_wake[1] += w_ind[1];
#pragma omp atomic
    w_wake[2] += w_ind[2];
}

Более эффективный способ суммирования в параллель состоит в том, чтобы каждый поток накапливал значения в частной переменной (только видимой этим потоком), получая при этом частичные суммы.

#pragma omp parallel 
{
    int wake0 = wake1 = wake2 = 0; // private variables

    #pragma omp for
    for(span=0;span<info.nospanelement;span++)
    {
        some_function(info,wakePtr[time][span],P,w_ind,1);

        //additions to be done each repeat
        wake0 += w_ind[0];  // accumulate in private variable
        wake1 += w_ind[1];
        wake2 += w_ind[2];
    }
// now we're out of the loop but still inside the parallel region
// so, let add up the partial sums
#pragma omp atomic
    w_wake[0] += wake0;
#pragma omp atomic
    w_wake[1] += wake1;
#pragma omp atomic
    w_wake[2] += wake2;
}

Обычно лучше, чтобы OpenMP управлял операциями сокращения, но если вам нужно сохранить результаты в массиве, то, вероятно, проще просто сделать это самостоятельно.

С другой стороны, если вам не нужен массив, вы можете просто сделать это:

int wake0 = wake1 = wake2 = 0; // SHARED variables this time
#pragma omp parallel for reduction(+ : wake0, wake1, wake2)
{
    for(span=0;span<info.nospanelement;span++)
    {
        some_function(info,wakePtr[time][span],P,w_ind,1);

        //additions to be done each repeat
        wake0 += w_ind[0];  // accumulate in private variable
        wake1 += w_ind[1];
        wake2 += w_ind[2];
    }
}
  • 0
    Мой OpenMP очень ржавый. Вы не можете сделать #pragma omp parallel for reduction(+ : w_wake[0], w_wake[1], w_wake[2]) ?
  • 0
    @RafaelLerm Я так и думал, но потом я погуглил о выполнении редукции для массивов, и по какой-то причине OpenMP не может этого сделать - за исключением Fortran, начиная с OpenMP 3.0 и с очень хорошим компилятором. Или, может быть, вы можете сделать это с помощью синтаксиса, который вы только что процитировали, я не могу быть уверен, не пытаясь.
Показать ещё 6 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню