избегать вложенной параллельной области - PullRequest
1 голос
/ 16 декабря 2011

Я хочу написать функцию, которая использует openMP параллелизм, но должна работать независимо от того, вызывается она из параллельной области или нет. Поэтому я использовал предложение if для подавления параллелизма, но это не работает, как я думал:

#include <omp.h>
#include <stdio.h>

int m=0,s=0;

void func()
{
  bool p = omp_in_parallel();
  // if clause to suppress nested parallelism
#pragma omp parallel if(!p)
  {
    /* do some massive work in parallel */
#pragma omp master
    ++m;
#pragma omp single
    ++s;
  }
}

int main()
{
  fprintf(stderr,"running func() serial:\n");
  m=s=0;
  func();
  fprintf(stderr," m=%d s=%d\n",m,s);

  fprintf(stderr,"running func() parallel:\n");
  m=s=0;
#pragma omp parallel
  func();
  fprintf(stderr," m=%d s=%d\n",m,s);
}

, который создает вывод

running func() serial:
 m=1 s=1
running func() parallel:
 m=16 s=16

Таким образом, первый вызов func() работал нормально: m и s получают значения 1, как они должны, но второй вызов func() из параллельной области действительно создает вложенный параллелизм (с 16 командами из 1 потока каждый), хотя это было подавлено. То есть директивы omp master и omp single связаны с предшествующей директивой omp parallel if(!p), а не с внешней параллельной областью.

Конечно, эту проблему можно исправить с помощью следующего кода

void work()
{
  /* do some massive work in parallel */
#pragma omp master
  ++m;
#pragma omp single
  ++s;
}

void func()
{
  if(omp_in_parallel())
    work();
  else
#pragma omp parallel
    work();
}

но для этого требуется определить дополнительную функцию и т. Д. Возможно ли сделать это в пределах одной функции (без повторения кода)?

Ответы [ 2 ]

2 голосов
/ 21 декабря 2011

Конструкции OpenMP всегда будут связываться с самой внутренней содержащей конструкцией, даже если она не активна.Поэтому я не думаю, что это возможно при сохранении #pragma omp parallel для обоих путей кода (по крайней мере, с предоставленной информацией о проблеме).

Обратите внимание, что это хорошо, что он ведет себя так, потому чтов противном случае использование условных выражений может легко привести к очень проблематичному (читай глючному) коду.Посмотрите на следующий пример:

void func(void* data, int size)
{
   #pragma omp parallel if(size > 1024)
   {
       //do some work
       #pragma omp barrier
       //do some more work
   }
}

...
#pragma omp parallel
{
   //create foo, bar, bar varies massively between different threads (so sometimes bigger, sometimes smaller then 1024
   func(foo, bar);
   //do more work
}

В общем случае программисту не нужно знать детали реализации вызываемых функций, только их поведение.Поэтому мне действительно не нужно заботиться о том, создает ли func вложенный раздел parallel или нет, и при каких именно условиях он создается.Однако, если barrier будет связываться с внешним parallel, если внутреннее неактивно, этот код будет содержать ошибки, так как некоторые потоки внешних секций parallel встречают barrier, а некоторые нет.Поэтому такие детали остаются скрытыми внутри самого внутреннего, содержащего parallel, даже если оно не активно.

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

0 голосов
/ 22 декабря 2011

Я посмотрел на стандарт openMP. Предложение if на самом деле несколько вводит в заблуждение, поскольку директива #pragma omp parallel не является условной (как я изначально думал). Вместо этого предложение if может ограничить количество потоков до 1, подавляя тем самым распараллеливание.

Однако это означает, что omp single или omp master не могут использоваться для поточных безопасных однократных операций записи глобальных общих переменных.

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