Как остановить параллельный регион OpenMP 2.0 - PullRequest
0 голосов
/ 21 января 2019

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

Я должен работать с Visual, поэтому мой OpenMP Lib устарел, и нет никакого способа обойти это. Следовательно, я думаю #omp cancel не будет работать

int progress_state = RunExport;
#pragma omp parallel
{
#pragma omp for
  for (int k = 0; k < foo.z; k++)
  for (int j = 0; j < foo.y; j++)
  for (int i = 0; i < foo.x; i++) {
    if (progress_state == StopExport) {
      continue;
    }

// do some fancy shit 

// yeah here is a condition for speed due to the critical
#pragma omp critical
    if (condition) {
      progress_state = StopExport;
    }
  }
}

1 Ответ

0 голосов
/ 21 января 2019

Вы должны сделать это простым способом "просто continue во всех оставшихся итерациях, если запрашивается отмена". Это может быть просто первая проверка в самом внешнем цикле (и учитывая, что у вас есть несколько вложенных циклов, которые, вероятно, не будут иметь измеримых накладных расходов).

std::atomic<int> progress_state = RunExport;

// You could just write #pragma omp parallel for instead of these two nested blocks.
#pragma omp parallel
{
#pragma omp for
  for (int k = 0; k < foo.z; k++)
  {
    if (progress_state == StopExport)
      continue;

    for (int j = 0; j < foo.y; j++)
    {
      // You can add break statements in these inner loops.
      // OMP only parallelizes the outermost loop (at least given the way you wrote this)
      // so it won't care here.
      for (int i = 0; i < foo.x; i++)
      {

        // ...

        if (condition) {
          progress_state = StopExport;
        }
      }
    }
  }
}

Вообще говоря, OMP не будет внезапно создавать новые потоки или завершать существующие, особенно в пределах одного параллельного региона. Это означает, что при выполнении еще нескольких крошечных итераций возникают небольшие накладные расходы. Это еще более верно, учитывая, что планирование по умолчанию в вашем случае, скорее всего, static, что означает, что каждый поток знает свой начальный и конечный индексы сразу. Другие режимы планирования должны вызывать во время выполнения OMP каждую итерацию (или каждые несколько итераций) для запроса дополнительной работы, но здесь этого не произойдет. Компилятор в основном увидит этот код для многопоточной работы:

// Not real omp functions.
int myStart = __omp_static_for_my_start();
int myEnd = __omp_static_for_my_end();
for (int k = myStart; k < myEnd; ++k)
{
  if (progress_state == StopExport)
    continue;

  // etc.
}

Вы можете попробовать не-атомный локальный поток "я должен отменить?" флаг, который начинается с false и может быть изменен только на true (что компилятор может понять и сложить в условие цикла). Но я сомневаюсь, что в любом случае вы увидите значительные издержки, по крайней мере, на x86, где int в любом случае атомарен.

что выглядит не элегантно

OMP 2.0 не совсем сияет в отношении элегантности. Я имею в виду, что для итерации по std::vector требуется как минимум один static_cast, чтобы заставить подпись замолчать -> предупреждения о преобразовании без знака. Поэтому, если у вас нет конкретных доказательств того, что этот шаблон вызывает проблемы с производительностью, нет особых причин не использовать его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...