Вот самый простой способ сделать это:
float sharedFsum = 0.f;
float masterFsum;
#pragma omp parallel
{
const int t = omp_get_thread_num();
while(iteration_condition)
{
float f = get_local_result(t);
// Manual reduction
#pragma omp update
sharedFsum += f;
// Ensure the reduction is completed
#pragma omp barrier
#pragma omp master
MPI_Bcast(&sharedFsum, ...);
// Ensure no other threads update sharedFsum during the MPI_Bcast
#pragma omp barrier
}
}
Операции atomi c могут быть дорогостоящими, если у вас много потоков (например, сотен). Лучший подход - позволить среде выполнения выполнить сокращение за вас. Вот лучшая версия:
float sharedFsum = 0;
#pragma omp parallel
{
const int threadCount = omp_get_num_threads();
float masterFsum;
while(iteration_condition)
{
// Execute get_local_result on each thread and
// perform the reduction into sharedFsum
#pragma omp for reduction(+:sharedFsum) schedule(static,1)
for(int i=0 ; i<threadCount ; ++i)
sharedFsum += get_local_result(i);
#pragma omp master
{
MPI_Bcast(&sharedFsum, ...);
// sharedFsum must be reinitialized for the next iteration
sharedFsum = 0.f;
}
// Ensure no other threads update sharedFsum during the MPI_Bcast
#pragma omp barrier
}
}
Примечания:
t
не защищен в вашем коде, используйте private(t)
в разделе #pragma omp parallel
чтобы избежать неопределенного поведения из-за состояния гонки. В качестве альтернативы, вы можете использовать переменные области видимости.
#pragma omp master
следует отдавать предпочтение условному идентификатору потока.
параллельно накладные расходы региона на каждой итерации убивают производительность ...
В большинстве случаев это происходит из-за (неявной) синхронизации / обмена данными или дисбаланса работы. Приведенный выше код может иметь ту же проблему, поскольку он довольно синхронный. Если это имеет смысл в вашем приложении, вы можете сделать его немного менее синхронным (и, следовательно, возможно, более быстрым), удаляя или перемещая барьеры относительно скорости MPI_Bcast
и get_local_result
. Однако это не так просто сделать правильно . Один из способов сделать это - использовать задачи OpenMP и мультибуферизацию .