Блокировка вложенной функции с помощью небезопасной переменной stati c - PullRequest
0 голосов
/ 05 января 2020

У меня есть функция memoize, которая читает и записывает данные c std::map, например:

int memoize(int i)
{
static std::map<int,int> map;
const auto iterator = memoizer.find(i);
if (iterator == memoizer.end())
  memoizer[i]=i+1;
else
  return iterator->second;
}

memoize вызывается другими функциями, которые вызываются другими функциями, которые вызывается .... функциями в main. Теперь, если в main у меня есть что-то вроде

#pragma omp parallel for
for (int i=0; i<1000; i+++)
  f(i); \\function calling memoize

for (int i=0; i<1000; i+++)
  g(i); \\function calling memoize

, тогда у меня проблема с первым l oop, поскольку std::map не является поточно-ориентированным. Я пытаюсь найти способ заблокировать карту stati c, только если используется openmp (таким образом, только для первого l oop). Я бы предпочел не переписывать все функции, чтобы получить дополнительный аргумент omp_lock_t.

Какой лучший способ добиться этого? Надеюсь, с наименьшим количеством макросов.

1 Ответ

3 голосов
/ 06 января 2020

Очень простым решением вашей проблемы было бы защитить как части чтения, так и обновления вашего кода с помощью директивы critical OpenMP . Конечно, чтобы уменьшить риск нежелательного взаимодействия / коллизии с каким-либо другим critical, который у вас уже может быть где-то еще в вашем коде, вы должны дать ему имя, чтобы четко идентифицировать его. И если ваша реализация OpenMP позволяет это (ie версия стандарта достаточно высока), а также, если у вас есть соответствующие знания, вы можете добавить подсказку о том, сколько разногласий вы ожидаете от этого например, обновление между потоками.

Затем я бы посоветовал вам проверить, дает ли эта простая реализация достаточную производительность, а это означает, что влияние директивы critical не слишком сильно с точки зрения производительности. Если вы довольны исполнением, оставьте все как есть. Если нет, то вернитесь с более точным вопросом, и мы посмотрим, что можно сделать.

Для простого решения код может выглядеть следующим образом (здесь есть подсказка, предполагающая, что ожидается высокий уровень конкуренции, это только пример для вас, а не мое истинное ожидание):

int memoize( int i ) {
    static std::map<int,int> memoizer;
    bool found = false;
    int value;
    #pragma omp critical( memoize ) hint( omp_sync_hint_contended )
    {
        const auto it = memoizer.find( i );
        if ( it != memoizer.end() ) {
           value = it->second;
           found = true;
        }
    }
    if ( !found ) {
        // here, we didn't find i in memoizer, so we compute it
        value = compute_actual_value_for_memoizer( i );
        #pragma omp critical( memoize ) hint( omp_sync_hint_contended )
        memoizer[i] = value;
    }
    return value;
}
...