在x86架构上使用OpenMP实现原子最小值操作

9
OpenMP是否支持C++11的原子最小值?如果OpenMP没有可移植的方法:是否有一种使用x86或amd64功能的方法来实现它?
在OpenMP规范中,我没有找到与C ++相关的内容,但Fortran版本似乎支持它。有关详细信息,请参见v3.1的2.8.5节。对于C ++,它声明:
binop是+、*、-、/、&、^、|、<<或>>之一。
但对于Fortran,它声明:
intrinsic_procedure_name是MAX、MIN、IAND、IOR或IEOR之一。
如果您对更多上下文感兴趣:我正在寻找一个无互斥锁的方法来执行以下操作:
vector<omp_lock_t>lock;
vector<int>val;

#pragma omp parallel
{
  // ...
  int x = ...;
  int y = ...;
  if(y < val[x]){
    omp_set_lock(&lock[x]);
    if(y < val[x])
      val[x] = y;
    omp_unset_lock(&lock[x]);
  }
}

我知道您可以使用reduce算法计算最小值。我知道在某些情况下,这种方法大大优于任何原子最小值方法。然而,我也知道在我的情况下不是这样的。

编辑:在我的情况下,稍微快一点的选项是

  int x = ...;
  int y = ...;
  while(y < val[x])
    val[x] = y;

但这不是原子操作。

所有新的GPU都具有此功能,而我在CPU上却缺少它。(请参见OpenCL的atom_min。)


这是C++98还是C++11? - user1071136
顺便问一下,为什么在你的情况下atomic-min更快?我遇到了类似的问题,reduction-min并没有提高性能,所以也许我应该尝试一下atomic-min。 - user1071136
@user1071136 我猜在幕后,互斥锁除了自旋循环之外什么都不做。直接编码可能允许编译器生成更好的代码,因此速度更快。然而,这显然取决于特定的OpenMP实现(并且这只是我个人的纯猜测)。我实际上对过于优化的优化器感到害怕,它会将 while(y < val[x]) val[x] = y; 转换为 if(y < val[x]) val[x] = y;,因为在 val[x] = y 之后,条件 y < val[x] 必定“显然”为假。 - B.S.
1
我不了解OpenMP,但是你可以在x86上使用“lock cmpxchg”来写入新值,仅当该值未更改时,并重复比较直到它停止更改。你的编译器可能为此提供了内置函数。 - ughoavgfhw
1个回答

6

针对 C++ 的 OpenMP 规范不支持原子最小值操作,C++11 也不支持。

我假设在你的算法中,x 可以计算出任何有效的索引,无论线程如何。我建议修改你的算法,让每个线程使用自己的 val 数组,然后在最后进行最终协调,这也可以通过索引并行化。这将完全避免锁和原子操作,并使你受益于分离每个线程的数据,即没有错误缓存共享的机会。换句话说,它应该更快。


查看 https://dev59.com/GmQo5IYBdhLWcg3wR9nD 以获取 C++11 解决方案;只需将 < 替换为 > 即可。 - MSalters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接