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

Как работает директива SECTIONS в дистрибутиве OpenMP?

В OpenMP при использовании omp sections будут ли потоки распределяться по блокам внутри разделов или каждый поток будет назначен каждому разделу?

Когда nthreads == 3:

#pragma omp sections
{
    #pragma omp section
    { 
        printf ("id = %d, \n", omp_get_thread_num());
    }

    #pragma omp section
    { 
        printf ("id = %d, \n", omp_get_thread_num());
    }
}

Вывод:

id=1
id=1

Но когда я выполняю следующий код:

#pragma omp sections
{
    #pragma omp section
    { 
        printf ("id = %d, \n", omp_get_thread_num());
    }

    #pragma omp section
    { 
        printf ("id = %d, \n", omp_get_thread_num());
    }
}

#pragma omp sections
{
    #pragma omp section
    { 
        printf ("id = %d, \n", omp_get_thread_num());
    }

    #pragma omp section
    { 
        printf ("id = %d, \n", omp_get_thread_num());
    }
}

Вывод:

id=1
id=1

id=2
id=2

Из этого вывода я не могу понять, что такое понятие разделов в OpenMP.

4b9b3361

Ответ 1

Я очень удивлен, что ни один из вопросов здесь не ответил на OP. Поскольку это один из первых результатов в google, я думаю, что важно прояснить эту тему, особенно для новичков, которые могут приземлиться на этой странице и быть еще более запутанными. Более того, некоторые ответы говорят о предложении nowait, о котором даже не упоминается в вопросе (я думаю, это произошло после редактирования вопроса). Это делает вещи еще более запутанными.

ОП удивлен тем, что он получает одинаковый идентификатор для разных разделов. В то время как wump корректно указывает, что порядок не является детерминированным, здесь причина намного проще: код, отправленный OP, никогда не будет выполняться параллельно, потому что ключевое слово "parallel" не появляется, если оно не заключено в параллель директивы. Поэтому это не очень полезный пример. Тот факт, что OP получил идентификаторы, отличные от 0, показывает, что, вероятно, его код был встроен в параллельную директиву. Однако это не ясно из его поста и может путать начинающих.

Минимальным разумным примером является (для первого примера, отправленного OP):

#pragma omp parallel sections
{
    #pragma omp section
    { 
        printf ("id = %d, \n", omp_get_thread_num());
    }

    #pragma omp section
    { 
        printf ("id = %d, \n", omp_get_thread_num());
    }
}

На моей машине это печатает

id = 0,
id = 1,

показывающий, что две секции выполняются разными потоками. Стоит отметить, что, однако, этот код не может извлекать больше parallelism, чем два потока: если он выполняется с большим количеством потоков, другие потоки не имеют никакой работы и будут просто сидеть без дела.

Ответ 2

Идея параллельных разделов - дать компилятору намек на то, что различные (внутренние) секции могут выполняться параллельно, например:

#pragma omp parallel sections
{
   #pragma omp section
   {
      /* Executes in thread 1 */
   } 
   #pragma omp section
   {
      /* Executes in thread 2 */
   } 
   #pragma omp section
   {
      /* Executes in thread 3 */
   } 
   /* ... */
}

Это подсказка для компилятора и не гарантируется, хотя это и должно произойти. Ваш результат - это то, что ожидается; он говорит, что в thread id 1 выполняется #sections и в потоке 2. Порядок вывода не является детерминированным, поскольку вы не знаете, какой поток будет выполняться в первую очередь.

Ответ 3

Измените первую строку из

#pragma omp разделы

в

#pragma omp параллельные секции

Директива

"parallel" гарантирует, что обе секции назначены двум потокам. Затем вы получите следующий вывод: id = 0, id = 1,

Ответ 4

Вам не хватает ключевого слова parallel. Ключевое слово parallel запускает запуск openmp параллельно.

Ответ 5

В соответствии с OpenMP standard 3.1, раздел 2.5.2 (акцент мой):

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

...

Каждому структурированному блоку в конструкции разделов предшествует, за исключением, возможно, первого блока, для которого директива предшествующего раздела является необязательной. Метод планирования Структурированные блоки среди потоков в команде - это реализация определяется. В конце разделов есть неявный барьер, если не указано условие nowait.

Итак, применяя эти правила к вашему делу, мы можем утверждать, что:

  • различные структурированные блоки, идентифицированные в директиве sections, выполняются один раз одним потоком. Другими словами, у вас всегда четыре отпечатка, в зависимости от количества потоков
  • блоки в первом sections будут выполняться (в недетерминированном порядке) до блоков во втором sections (также выполняемом в недетерминированном порядке). Это связано с неявным барьером в конце конструкций совместного использования.
  • планирование реализовано, так что вы не можете контролировать, какой поток был назначен данному разделу

Таким образом, ваш результат связан с тем, как планировщик решил назначить разные блоки для потоков в команде.

Ответ 6

Может оказаться полезным добавить дополнительную информацию в выходную строку и добавить дополнительные разделы (если у вас есть счетчик потоков)

#pragma omp parallel sections
{
    #pragma omp section
    {
        printf ("section 1 id = %d, \n", omp_get_thread_num()); 
    }
    #pragma omp section
    {
        printf ("section 2 id = %d, \n", omp_get_thread_num());
    }
    #pragma omp section
    {
        printf ("section 3 id = %d, \n", omp_get_thread_num());
    }
}

Затем вы можете получить более интересный вывод следующим образом:

section 1 id = 4,
section 3 id = 3,
section 2 id = 1,

который показывает, как разделы могут выполняться в любом порядке, любым доступным потоком.

Ответ 7

Обратите внимание, что 'nowait' сообщает компилятору, что потокам не нужно ждать до exit раздела. В Fortran 'nowait' идет в конце цикла или секции, что делает это более очевидным.

Ответ 8

Если вы действительно хотите начать разные потоки в разных разделах, предложение nowait сообщает компилятору, что потокам не нужно ждать, чтобы войти в раздел.

#pragma omp parallel sections nowait
{
   ...
}