Имеет ли Concurrency :: parallel_for команду, аналогичную omp_set_lock? - PullRequest
0 голосов
/ 31 марта 2020

У меня есть класс (скажем, частица), который имеет переменную (скажем, param1):

class particle
{
    double param1;
    . . .
    omp_lock_t particle_lck;
    . . .
};

и вектор std ::, содержащий несколько экземпляров класса частиц,

vector <particle> Particles;

В параллельной omp для l oop я использую команды ниже для безопасного обновления «param1» в вычислениях:

omp_set_lock(&currentParticle->particle_lck);
currentParticle->param1 += anything
omp_unset_lock(&currentParticle->particle_lck);

Теперь я собираюсь преобразовать свой код из библиотеки openMP в библиотеку параллелизма. Интересно, есть ли какая-либо эквивалентная команда для использования в Concurrency :: parallel_for l oop вместо omp_set_lock, которая может блокировать объект во время обновления?

Заранее спасибо.

1 Ответ

1 голос
/ 03 апреля 2020

Я предполагаю, что под библиотекой Concurrency вы подразумеваете Microsoft Concurrency Runtime. Ваш вариант использования на самом деле является критическим разделом, и для этого Concurrency предоставляет concurrency::critical_section, который является невозвращаемой блокировкой мьютекса:

using namespace concurrency;

class particle
{
    double param1;
    . . .
    critical_section particle_lck;
    . . .
};

Тогда критический раздел становится:

currentParticle->particle_lck.lock();
currentParticle->param1 += anything;
currentParticle->particle_lck.unlock();

Если вы предпочитаете ограниченный подход, используйте concurrency::critical_section::scoped_lock:

{
   critical_section::scoped_lock guard(currentParticle->particle_lck);
   currentParticle->param1 += anything;
}

scoped_lock - простая оболочка. Он принимает ссылку на объект critical_section и вызывает lock() в конструкторе, а затем unlock() в деструкторе, поэтому он снимает блокировку, когда выходит из области видимости.


Как объяснено Джим Коун ie, использование блокировок для чего-то, что может быть сделано более эффективно с помощью операции atomi c, является излишним. В OpenMP обычно делают:

#pragma omp atomic update
currentParticle->param1 += anything;

Atomi c Операции в стандартном C ++ требуют использования специальных типов Atomi c, и они доступны только для типов с плавающей запятой, начиная с C +. +20, поэтому ваш код будет (при условии, что компилятор C ++ 20):

#include <atomic>

class particle
{
    std::atomic<double> param1;
    . . .
};

Обновление значения:

currentParticle->param1.fetch_add(anything, std::memory_order_relaxed);

Параллелизм не предоставляет свои собственные атомы c типов , Вместо этого он полагается на класс combinable, чтобы обеспечить эквивалент для предложения reduction OpenMP.

...