Связь между потоками OpenMP

0

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

Например:

    bool FirstDone = false; // This is a global variable
    ...
    #pragma omp parallel for
    for(int i=0;i<max;i++)
    {
        while(!FirstDone && i>0){}

        if(i==0)
        {
            // Do something
            FirstDone = true;
        }
    }

Может ли кто-нибудь пролить свет на то, почему это не работает?

Теги:
openmp

6 ответов

2
Лучший ответ

выполните первую итерацию за пределами цикла, начните с я = 1, если вы хотите продолжить свою логику, измените FirstDone на volatile, но он все равно не будет работать, поскольку нет гарантии упорядочения потоков

  • 0
    Я предпочел бы сделать это внутри цикла через какое - то барьер на> 0 нитей. Цикл довольно длинный и сложный ... копирование всего содержимого только для того, чтобы сделать шаг i = 0, мне кажется неуклюжим.
  • 3
    переместить код всего цикла в функцию
Показать ещё 1 комментарий
2

Я попробую здесь перефразировать ответ @HighPerformanceMark более явным образом (т.е. С некоторыми эскизами кода для поддержки операторов). Чтобы исправить идеи, скажем, что серийная версия вашего цикла выглядит так:

for(int ii = 0; ii < max; ii++)
{   
    // Do a lot of work based on ii
    if(ii==0)
    {
        //////////////////////////////////////////////////
        // Do something special for the first iteration //
        //////////////////////////////////////////////////
    }
}

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

// Move the loop body into a function
void loopIteration(const size_t ii) {
    // Do a lot of work based on ii
}

#pragma omp parallel
{
// Single directive: the first one enters, the other wait at the implicit barrier
#pragma omp single
    {
        loopIteration(0);
        //////////////////////////////////////////////////
        // Do something special for the first iteration //
        //////////////////////////////////////////////////
    } // single: implicit barrier
// Loop work-sharing construct on the remaining iterations
#pragma omp for
    for(int ii = 1; ii < max; ii++)
    {   
       loopIteration(ii);         
    } // for: implicit barrier
} // parallel

Основные идеи - переместить тело цикла в функцию, чтобы избежать дублирования кода и явно развернуть первую итерацию из цикла.

  • 0
    А, значит, вы хотите поместить код основного цикла во внешнюю функцию. Я ценю эту идею - и понимаю, что это сработает, - но в моем случае это громоздко. У меня есть много общих переменных, которые можно передать по ссылке, но это сделало бы очень длинную сигнатуру функции. Я использую решение @Ilya Bursov с «volatile» логическим значением, и оно кажется хорошим решением.
2

Вы можете перенести первую итерацию внутри single конструкции OpenMP. Это гарантирует, что первый поток, который встретит конструкцию, выполнит его и что все остальные потоки будут ждать, пока он не будет закончен, прежде чем продолжить с остальными вычислениями.

  • 0
    Это вводит условие гонки - поток i = 0 должен поразить эту единственную конструкцию, прежде чем другие будут работать, как предполагалось.
  • 0
    @paradiso Нет, это правильно: итерация i = 0 должна выполняться перед другими итерациями, в зависимости от того, какой поток ее выполняет!
Показать ещё 2 комментария
1

Я думаю, вы можете достичь этого, используя ordered предложение и область, например.

#pragma omp parallel for ordered
for(int i=0;i<max;i++)
{
    #pragma omp ordered
    if (i == 0)
    {
        // Do stuff in the first iteration, others wait.
    }

}

Это может привести к снижению производительности.

  • 0
    Мне не на 100% ясно, что это сработает, но пока это мой любимый вариант .. Я попробую это немного
1

Используйте этот

 #pragma omp parallel for

он начинается по умолчанию с вашей первой итерацией.

  • 0
    Я не согласна Можете ли вы объяснить больше или предоставить некоторые ссылки?
0

Вы пробовали просто удалить цикл while и while и установить барьер после инструкции if?

  • 0
    Абсолютно разумное решение, хотя в моем конкретном случае я не могу поместить оператор if в начало цикла (несмотря на то, что мой пример кода поместил его там)
  • 0
    Вы не можете поставить барьер после оператора if как вы не можете гарантировать, что каждый поток встретит одинаковую последовательность барьеров (и это сделает программу не соответствующей стандарту)
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню