0

我有一个类(比如粒子),它有一个变量(比如 param1):

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

和一个包含粒子类的一些实例的 std::vector,

vector <particle> Particles;

在 omp 并行 for 循环中,我使用以下命令在计算中安全地更新“param1”:

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

现在,我要将我的代码从 openMP 转换为 Concurrency 库,我想知道在 Concurrency::parallel_for 循环中是否有任何等效命令可以使用,而不是 omp_set_lock,它可以在更新时锁定对象?

提前致谢。

4

1 回答 1

1

我假设并发库是指 Microsoft 的并发运行时。您的用例实际上是一个关键部分,并且 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()在析构函数中调用,因此当它超出范围时它会释放锁。


正如 Jim Cownie 所解释的,将锁用于可以通过原子操作更有效地完成的事情是一种矫枉过正的做法。在 OpenMP 中,通常会这样做:

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

标准 C++ 中的原子操作需要使用特殊的原子类型,而这些原子类型仅适用于从 C++20 开始的浮点类型,因此您的代码将是(假设 C++20 编译器):

#include <atomic>

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

更新值:

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

并发不提供自己的原子类型。相反,它依赖于combinable类来提供等效于 OpenMP 的reduction子句。

于 2020-04-02T22:33:15.957 回答