#pragma omp parallel
выполняет следующий код параллельно в нескольких потоках. Следовательно, несколько циклов будут работать одновременно. Все эти версии будут извлекать глобальные переменные и обновлять их более или менее одновременно, и вы не можете просто контролировать то, что происходит.
Например, вполне возможно, что alfaIter модифицируется неконтролируемым образом, что приводит к неопределенному поведению.
Вот как процессор может обработать первые строки вашего кода
1 read alfaIter in local var (register)
2 var++
3 write register var in alfaIter
4 fetch alfaIter to call pow and put it in stack or register
5 call pow(...)
Позвольте сказать, что эти инструкции 1a 2a 3a 4a 5a в потоке A и 1b 2b 3b 4b 5b в потоке B.
Что может быть фактическим порядком исполнения?
Предположим, что это
1a 2a 3a 4a 5a 1b 2b 3b 4b 5b.
Поведение будет таким, как ожидалось. Pow вызывается в потоке A с alfaIter = 1 и в потоке B с alfaIter = 2
Но другой порядок может привести к другому поведению
Например,
1a 1b (both local regs in thrd A and B have initial value of 0)
2a 3a (alfaIter=1 written back to memory by thead A)
2b 3b (alfaIter=1 written back to memory by thead B)
4a 4b 5a 5c (pow called by both threads with the same value of alfaIter=1)
Поскольку возможно любое упорядочение, поведение вашего цикла непредсказуемо.
Решение сделать его предсказуемым - с помощью атомарных операций.
В этом случае вы можете убедиться, что доступ к памяти является последовательным и что поведение цикла while будет таким, как ожидалось.
Но у этого есть главный недостаток. Атомарные операции имеют длину очень и обычно требуют ~ 100 циклов на современных процессорах. Это значительно замедлит ваш код и сделает его на намного медленнее, чем последовательная версия.
В общем, лучше всего использовать цикл, но это не представляется возможным для вас.
Я бы посоветовал визуализировать большинство var локально, запустить параллельный поток, увеличивающий alfaIter на 2 (или на количество потоков), и просто использовать глобальные действия для условия завершения.
Пример кода:
#pragma omp parallel num_threads(2)
{
int alfaIter=omp_get_thread_num();
int step=omp_get_num_threads();
float alfa;
float testX[dim],b;
// and maybe d[] and g[] but I do not understand what they do
while (alfaSet == false) { // no problem to read a global var
alfaIter+=step;
alfa = pow(gamma, alfaIter - 1);
b = 0;
for (i = 0; i < dim; i++) {
testX[i] = x[i] + alfa * d[i];
}
for (i = 0; i < dim; i++) {
b += d[i] * g[i];
}
if (shanno(testX, dim) - shanno(x, dim) <= delta * alfa * b) {
#pragma omp critical
if (! alfaSet) { // you can do safe operations here
alfaIter = 0;
alfaSet = true;
}
}
}
}
Это не проверено, но может быть отправной точкой.