Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/154.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在OpenMP中对struct(x,y,z)变量使用原子操作 我在C++中开发了一个OpenMP代码(编译器是g++4.82)。在代码的一部分中,我需要对结构数据执行原子添加。strct的定义如下: struct real3 { float x; float y; float z; };_C++_Struct_Openmp_Atomic - Fatal编程技术网

在OpenMP中对struct(x,y,z)变量使用原子操作 我在C++中开发了一个OpenMP代码(编译器是g++4.82)。在代码的一部分中,我需要对结构数据执行原子添加。strct的定义如下: struct real3 { float x; float y; float z; };

在OpenMP中对struct(x,y,z)变量使用原子操作 我在C++中开发了一个OpenMP代码(编译器是g++4.82)。在代码的一部分中,我需要对结构数据执行原子添加。strct的定义如下: struct real3 { float x; float y; float z; };,c++,struct,openmp,atomic,C++,Struct,Openmp,Atomic,我为它定义了加法运算符,如下所示: inline real3 operator+(real3 a, real3 b) { return make_real3(a.x + b.x, a.y + b.y, a.z + b.z); } 我在代码的所有部分都使用这个struct。在程序的一部分中,我需要以原子方式执行添加操作: real3 * m_cforce; real3 fn, ft; int i; /* . . . . some code is here */ #pragma o

我为它定义了加法运算符,如下所示:

inline real3 operator+(real3 a, real3 b)
{ 
  return make_real3(a.x + b.x, a.y + b.y, a.z + b.z);
}
我在代码的所有部分都使用这个struct。在程序的一部分中,我需要以原子方式执行添加操作:

real3 * m_cforce;
real3 fn, ft;
int i;
/*
 . . . .  some code is here 

*/

#pragma omp atomic
m_cforce[i] = m_cforce[i] + (fn + ft);
编译不接受结构real3作为原子加法的操作数。一种解决方案是使用以下代码:

#pragma omp atomic
m_cforce[i].x = m_cforce[i].x + (fn + ft).x;
#pragma omp atomic
m_cforce[i].y = m_cforce[i].y + (fn + ft).y;
#pragma omp atomic
m_cforce[i].z = m_cforce[i].z + (fn + ft).z;

这样,我使用原子学的次数增加了3倍,这将花费我更多的时间。有没有什么方法可以节省我的计算开销

OpenMP原子需要在标量值(简单类型)上运行。原子旨在通过运行时映射到内核级甚至指令级原子。如果不了解您的问题,很难给出一个答案,但对于这类问题,通常有一些建议:

  • 使用线程局部变量(如果可能)。如果只有一个线程可以对其进行写入,那么可以在大部分计算中避免原子,然后在最后减少原子
  • 上面的3原子方法可以工作,但它允许多个线程添加到同一real3中,可能是交错的。由于浮点是非关联的,这可能会导致更不确定的结果。总的来说,这是一个不错的选择
  • 每个共享real3使用OpenMP锁。使用critical就像在包含的代码段周围使用单个锁一样。如果您按照real3使用锁,只要它们接触不同的real3,它们就可以并行运行。OpenMPs锁不是最快的,但它们应该比临界值快
    • @user2548418:

      这是一种多实体模拟,其中所有实体(从0到N-1)相互作用。在第一步中,有一个确定成对交互的搜索。然后在所有物体上都有一个循环来计算相互作用(这是一个平行的部分,有一个平行的计数器i)。简单地说,每个物体(i)可以与系统中的0到20个物体(j)相互作用。当我计算相互作用力时,我应该把这些力加到每个物体的总作用力中(I和j) 上面所演示的代码是执行此添加的部分,因此如果您希望这部分完成,请考虑以下内容:

      #pragma omp atomic
      m_cforce[i].x = m_cforce[i].x + (fn + ft).x;
      #pragma omp atomic
      m_cforce[i].y = m_cforce[i].y + (fn + ft).y;
      #pragma omp atomic
      m_cforce[i].z = m_cforce[i].z + (fn + ft).z;
      
      #pragma omp atomic
      m_cforce[j].x = m_cforce[j].x - (fn + ft).x;
      #pragma omp atomic
      m_cforce[j].y = m_cforce[j].y - (fn + ft).y;
      #pragma omp atomic
      m_cforce[j].z = m_cforce[j].z - (fn + ft).z;
      
      因为每个线程将修改两个不同的内存位置:一个在i位置,对应于迭代计数器,另一个在j位置,是随机的,可以是从0到N-1的任何数字。这种依赖性不允许我考虑每个线程的私有标量Real3。存在一种解决办法。我为每个线程分配一个real3[N]的向量,然后在“parallel for”的末尾使用一个约化和来计算每个物体上的总作用力。这可能具有挑战性,因为它会降低捕获效率(原子也会这样做)。所以,我应该将这个解决方案与使用原子学进行比较

      我知道浮点运算不是关联的。但在我的例子中,它不是限制性的,因为力的顺序没有太大的不同,当操作a+(b+c)变成(a+b)+c时,误差会非常小


      我不会在代码中使用锁,否则第一个和第二个解决方案的性能会非常差

      首先,将
      fn+ft
      存储在某处。您可以使用
      critical
      ,但它的开销比atomics大。@MohitJain I将其删除。@dmg I使用critical,它比使用三个原子加法慢5倍。因为它一次只运行一个线程,但是atomic会锁定内存位置,并允许其他线程继续运行,而不是让那些要访问同一内存位置的线程继续运行。谢谢您的快速回复。@dmg-我使用了critical,它比使用三个原子加法慢5倍。因为它一次只运行一个线程,但是atomic会锁定内存位置,并允许其他线程继续运行,而不是让那些要访问同一内存位置的线程继续运行。谢谢您的快速回复。@user3672271
      atomic
      s依靠硬件提供快速的无锁操作,而
      critical
      是一种通用的全锁方法。@user2548418:请参见上面的postFrom迭代变量i,它如何确定与哪个j交互?是否可以通过i*j迭代将i中j的嵌套循环变成一个循环?如果线程只添加到主迭代变量中,则可以删除所有原子。这将需要计算两次力(每端一次),但这将消除对所有原子的需要,@user2548418 J是完全随机的。N的大小约为100000到1000000。我真的不能确定j。至少,如果你复制m_c力,你可以使用一半的原子。当为我写作时,不要使用原子学和操作一份m_cforce。当写j时,使用另一个副本,并使用原子。最后,添加不带原子的两个副本。