Правильный способ переопределения минимальных / максимальных сокращений OpenMP с помощью сброса
Несколько дней назад мне пришло в голову, что фрагмент кода для реализации минимального / максимального сокращения OpenMP, который я использовал довольно часто, может на самом деле быть неправильным:
В некоторых случаях, когда условие сокращения OpenMP min-max было недоступно (старая версия OpenMP) или мне также требовался индекс для максимального значения, я использовал код, подобный этому:
#pragma omp parallel private(myMax,myMax_idx) shared(globalMax,globalMax_idx)
{
#pragma omp for
for (...) {
}
if (myMax >= globalMax) {
#pragma omp critical
{
if ((myMax > globalMax)||(myMax == globalMax && globalMax_idx < myMax_idx) {
globalMax = myMax;
globalMax_idx = myMax_idx;
}
}
}
}
Теперь мне пришло в голову, что этот код может на самом деле давать неправильные результаты, потому что совместно используемая переменная НЕ означает, что все потоки обращаются к одной и той же части памяти, но они могут использовать личную копию, которая может быть устаревшей со всеми другими потоками. Так что мне нужно использовать #pragma omp flush
синхронизировать переменную.
[...]
#pragma omp flush(globalMax)
if (myMax > globalMax) {
#pragma omp critical
{
if (myMax > globalMax) globalMax = myMax;
}
}
[...]
В работе М. Сюсса и др. "Типичные ошибки в OpenMP и как их избежать" эта реализация описывается как
По сути это повторная реализация редукции с использованием оператора max.
Но мне интересно, верен ли этот фрагмент кода, потому что я не вижу, чтобы поток записи сбрасывал его версию globalMax
в память.
Также в случае поиска по индексу мне нужно будет также сбросить globalMax_idx
переменная. Правильно?
Этот вопрос отчасти связан с
- Алгоритмы OpenMp C++ для min, max, медиана, среднее, но принятый ответ на этот вопрос не использует
flush
вообще, так что я не уверен, действительно ли это надежно. - explict flush direcitve с OpenMP: когда это необходимо и когда полезно, ссылается на этот учебник, в котором говорится, что критический регион выполняет сброс при входе и выходе (хотя я еще не нашел эту информацию в другом месте, хотя...), что сделало бы мою наивную реализацию и правильный ответ на вопрос выше.
Так что, если Код из "Типичных ошибок в OpenMP" предполагает, что критическая область сбрасывается, то стоит ли явно сбрасывать globalMax
переменная перед if
?
Какой код я должен использовать?