Pytanie Równoległa pętla OpenMP z instrukcją break


Wiem, że nie można napisać oświadczenia o przerwaniu dla pętli OpenMP, ale zastanawiałem się, czy istnieje jakieś obejście, podczas gdy wciąż korzystam z równoległości. Zasadniczo mam pętlę "for", która przechodzi przez elementy dużego wektora, szukając jednego elementu, który spełnia pewien warunek. Jednak jest tylko jeden element, który spełni warunek, więc gdy okaże się, że możemy wyjść z pętli, Z góry dziękuję

for(int i = 0; i <= 100000; ++i)
  {
    if(element[i] ...)
     {
          ....
          break;
      }
   }

21
2018-03-20 19:45


pochodzenie


jesteś zobowiązany do omp? - inf
związane z: Jak w sposób idiomatyczny oderwać się od zagnieżdżonej równoległej (OpenMP) pętli Fortrana? - jfs


Odpowiedzi:


Możesz spróbować ręcznie zrobić to, co robi pętla openmp, używając pętli while:

const int N = 100000;
std::atomic<bool> go(true);
uint give = 0;

#pragma omp parallel
{
    uint i, stop;

    #pragma omp critical
    {
        i = give;
        give += N/omp_get_num_threads();
        stop = give;

        if(omp_get_thread_num() == omp_get_num_threads()-1)
            stop = N;
    } 


    while(i < stop && go)
    {
        ...
        if(element[i]...)
        {
            go = false;
        }
        i++;
    }
}

W ten sposób musisz przetestować "go" w każdym cyklu, ale to nie powinno mieć większego znaczenia. Ważniejsze jest to, że odpowiadałoby to "statycznej" pętli for, która jest przydatna tylko wtedy, gdy można oczekiwać, że wszystkie iteracje będą trwały w podobnym czasie. W przeciwnym razie 3 wątki mogą być już zakończone, a jeden wciąż ma do połowy ...


7
2018-03-21 21:36



Technicznie, musisz przeczytać go atomowo. Również model pamięci gwarantuje brak widoczności, chyba że dodasz seq_cst do obu operacji atomowych. - Zulan
@Zulan, Prawidłowo, podczas gdy nie ma większego niebezpieczeństwa w praktyce (z wyjątkiem jakiejś dodatkowej pracy), odpowiedź jak technicznie zawiera wyścig danych. W dzisiejszych czasach (z C ++ 11) zdecydowanie sugerowałbym użycie a std::atomic<bool> dla go. Odpowiednio edytuję odpowiedź. - Haatschii


Zobacz ten fragment:

volatile bool flag=false;

#pragma omp parallel for shared(flag)
for(int i=0; i<=100000; ++i)
{    
    if(flag) continue;
    if(element[i] ...)
    {
          ...
          flag=true;
    }
}

Ta sytuacja jest bardziej odpowiednia dla pthread.


17
2018-03-23 09:03





Prawdopodobnie bym to zrobił (skopiowałem trochę z yyfn)

volatile bool flag=false;

for(int j=0; j<=100 && !flag; ++j) {
  int base = 1000*j;
  #pragma omp parallel for shared(flag)
  for(int i = 0; i <= 1000; ++i)
  {

    if(flag) continue;
    if(element[i+base] ...)
     {
          ....
          flag=true;
      }
   }
}

2
2018-03-23 09:14





Jednym ze sposobów na to jest ustawienie i do liczby, która przerwie pętlę. Ponieważ masz ustawioną pętlę, aby kontynuować działanie podczas i ≤ 100000, możesz przerwać pętlę, ustawiając ją 100001:

for(int i = 0; i <= 100000; ++i)
{
    if(element[i] ...)
    {
        ....
        i = 100001; // break
    }
}

Możesz jednak użyć czystszego rozwiązania, podczas gdy ty bool wskazujące, czy przerwać:

bool shouldBreak = false;
for(int i = 0; i <= 100000 && !shouldBreak; ++i)
{
    if(element[i] ...)
    {
        ....
        shouldBreak = true;
    }
}

1
2018-01-18 19:45



Gdzie umieścisz #pragma omp parallel for dyrektywa? . Druga opcja powoduje, że gcc narzeka na: error: invalid controlling predicate - xyz
nie powinieneś zmieniać wartości zmiennej pętli (i) na OpenMp ... A także warunek pętli z! = jest niedozwolony dla #pragma omp dla - sharp_c-tudent


bool foundCondition = false;
#pragma omp parallel for
for(int i = 0; i <= 100000; i++)
{
    // We can't break out of a parallel for loop, so this is the next best thing.
    if (foundCondition == false && satisfiesComplicatedCondition(element[i]))
    {
        // This is definitely needed if more than one element could satisfy the
        // condition and you are looking for the first one.  Probably still a
        // good idea even if there can only be one.
        #pragma omp critical
        {
            // do something, store element[i], or whatever you need to do here
                ....

            foundCondition = true;
        }
    }
}

0
2018-05-14 01:11





Oto prostsza wersja zaakceptowanej odpowiedzi.

int ielement = -1;
#pragma omp parallel
{
    int i = omp_get_thread_num()*n/omp_get_num_threads();
    int stop = (omp_get_thread_num()+1)*n/omp_get_num_threads();        
    for(;i <stop && ielement<0; ++i){
        if(element[i]) {
            ielement = i;
        }
    }
}

0
2018-05-14 08:39