Подтвердить что ты не робот

Параллельный цикл OpenMP с инструкцией break

Я знаю, что вы не можете иметь оператор break для цикла OpenMP, но мне было интересно, есть ли способ обхода проблемы, но при этом выигрывает от parallelism. В основном у меня есть цикл "for", который перемещается по элементам большого вектора, ища один элемент, который удовлетворяет определенному условию. Однако есть только один элемент, который будет удовлетворять условию, поэтому как только это будет найдено, мы можем выйти из цикла, заранее спасибо

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

Ответ 1

Вы можете попытаться вручную сделать то, что делает цикл openmp for, используя цикл 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++;
    }
}

Таким образом, вам нужно протестировать "идти" на каждый цикл, но это не должно иметь большого значения. Более важным является то, что это будет соответствовать "статическому" циклу omp for, что полезно только, если вы можете ожидать, что все итерации будут занимать аналогичное количество времени. В противном случае 3 потока могут быть уже закончены, пока еще есть половина пути, чтобы получить...

Ответ 2

Смотрите этот фрагмент:

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;
    }
}

Эта ситуация более подходит для pthread.

Ответ 3

Я бы, вероятно, сделал (скопировал бит из 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;
      }
   }
}

Ответ 4

Один из способов сделать это - установить i на число, которое разбивает цикл. Поскольку у вас есть цикл для продолжения работы во время i ≤ 100000, вы можете разбить цикл, установив его на 100001:

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

Возможно, вы захотите использовать более чистое решение, в то время как вы создаете bool, указывающий, следует ли прерывать:

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

Ответ 5

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;
        }
    }
}

Ответ 6

Вот более простая версия принятого ответа.

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;
        }
    }
}