Атомарное сравнение и подкачка OpenMP

#openmp #atomic

#openmp #атомарный

Вопрос:

У меня есть общая переменная s и частная переменная p внутри параллельной области.

Как я могу сделать следующее атомарно (или, по крайней мере, лучше, чем с critical разделом):

 if ( p > s )
    s = p;
else
    p = s;
 

Т.е. Мне нужно обновить глобальный максимум (если локальный максимум лучше) или прочитать его, если он был обновлен другим потоком.

Ответ №1:

OpenMP 5.1 ввел compare предложение, которое разрешает операции сравнения и подкачки (CAS), такие как

 #pragma omp atomic compare
if (s < p) s = p;
 

В сочетании с capture предложением вы должны быть в состоянии достичь того, чего хотите:

 int s_cap;

// here we capture the shared variable and also update it if p is larger
#pragma omp atomic compare capture
{
   s_cap = s;
   if (s < p) s = p;
}

// update p if the captured shared value is larger
if (s_cap > p) p = s_cap;
 

Единственная проблема? Спецификация 5.1 очень новая, и на сегодняшний день (2020-11-27) ни один из распространенных компиляторов, т. Е. Доступных на Godbolt, не поддерживает OpenMP 5.1. Смотрите Здесь более или менее актуальный список. Добавление compare по-прежнему указано как невостребованная задача на странице OpenMP Clang. GCC все еще работает над полной поддержкой OpenMP 5.0, и trunk сборка на Godbolt не распознает compare . Компилятор oneAPI от Intel может поддерживать или не поддерживать его — он недоступен на Godbolt, и я не могу заставить его скомпилировать код OpenMP.

На данный момент лучше всего использовать atomic capture в сочетании с атомарным CAS, зависящим от компилятора, возможно, в цикле.

Комментарии:

1. Но даже в таком случае у вас все еще есть условие гонки, если у вас есть поток, обновляющий «ы» в «захвате атомарного сравнения pragma omp», а другой уже выполняет if (s_cap> p)

2. s_cap фиксирует значение s во время выполнения атомарной конструкции. Если p было больше, s обновляется внутри атома и (s_cap > p) после того, как оно равно false, поэтому p остается неизменным. Если p значение было ниже, s оно не обновляется, но p обновляется до значения s_cap , т. Е. Значения s , которое было во время выполнения атомарного. Конечный результат такой же, как при выполнении if (p > s) s = p; else p = s; в критической секции.

3. Да, спасибо, теперь я понял. Мне все еще трудно представить, где на самом деле имеет смысл иметь что-то вроде этого кода (пример OP). Если только внутри упорядоченного конструктора.

4. @dreamcash У меня есть несколько потоков, которые итеративно ищут global max. Каждый новый глобальный максимум уменьшает пространство поиска для каждого потока. Итак, если «этот» поток обнаружил новый максимум, я хочу сообщить об этом другим потокам. Если глобальный максимум был обновлен другим потоком, «этот» поток хочет получить новый глобальный максимум, чтобы сузить пространство поиска «этого» потока

5. Если вам нужно максимальное сокращение, по крайней мере, время кода с использованием предложения сокращения. Вы также можете использовать предложение сокращения, если вам действительно нужно местоположение max. Трудно понять, как знание текущего значения помогает сократить вычисления в других потоках… Покажите нам реальный код!