Первый if ( d < dm )
находится за пределами критической секции 1003 * и может быть причиной состояния гонки.Его следует удалить, поскольку в разделе критический он уже есть.Если ваша цель состоит в том, чтобы не заходить слишком часто в критическую часть, то это не способ сделать это (см. Ниже).Возможно, вам придется вручную сбросить dm (см. здесь для некоторых пояснений по #pragma omp flush
).
Функция distancia
также может быть не поточно-ориентированной (то есть полагаться на некоторые глобальныепеременная, которая не может быть одновременно отредактирована несколькими потоками).
Кроме того, это нормально, если результат отличается, если некоторые значения расстояния равны.Поскольку не существует правила для конкретной обработки этого случая (т. Е. Взять наименьшее im
), индекс первого найденного минимального значения будет сохранен: он может не совпадать в последовательной и параллельной версиях, так как итерациине выполняется в том же порядке.
Если вычисление функции distancia
не требует интенсивной загрузки ЦП, ваш код, вероятно, будет работать медленнее, чем последовательный код по многим причинам.Примечательно, что накладные расходы синхронизации критической секции и проблема совместного использования кэша с переменной dm
.Лучше использовать подход сокращения, где каждый поток вычисляет минимум любой итерации, которую он дал обработке, и глобальный минимум принимается как наименьший локальный минимум из всех потоков.
float dm=INFINITY;
int im=-1;
#pragma omp parallel shared(dm,im)
{
// Declare private variables
float d,dmin_thread,imin_thread;
dmin_thread=INFINITY;
imin_thread=-1;
// loop through i
#pragma omp for
for ( i = 0 ; i < nt1 ; i++ ) {
d = some_function(i);
// the following lines operate on thread-private variables
if ( d < dmin_thread) {
dmin_thread= d;
imin_thread= i;
}
}// end for
// Reduction part after the loop has been completed
// The critical section is entered only once by each thread
#pragma omp critical
{
if ( dmin_thread < dm) {
dm = dmin_thread;
im = imin_thread;
}
}//end critical
}//end parallel
if(im==-1)
throw_some_error();
else
do_something_with(im);