У меня есть цикл 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;
}
}
Может ли кто-нибудь пролить свет на то, почему это не работает?
выполните первую итерацию за пределами цикла, начните с я = 1, если вы хотите продолжить свою логику, измените FirstDone на volatile, но он все равно не будет работать, поскольку нет гарантии упорядочения потоков
Я попробую здесь перефразировать ответ @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
Основные идеи - переместить тело цикла в функцию, чтобы избежать дублирования кода и явно развернуть первую итерацию из цикла.
Вы можете перенести первую итерацию внутри single
конструкции OpenMP. Это гарантирует, что первый поток, который встретит конструкцию, выполнит его и что все остальные потоки будут ждать, пока он не будет закончен, прежде чем продолжить с остальными вычислениями.
i = 0
должна выполняться перед другими итерациями, в зависимости от того, какой поток ее выполняет!
Я думаю, вы можете достичь этого, используя 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.
}
}
Это может привести к снижению производительности.
Используйте этот
#pragma omp parallel for
он начинается по умолчанию с вашей первой итерацией.
Вы пробовали просто удалить цикл while и while и установить барьер после инструкции if?
if
как вы не можете гарантировать, что каждый поток встретит одинаковую последовательность барьеров (и это сделает программу не соответствующей стандарту)