使用重载运算符减少OpenMP

时间:2013-04-23 18:04:49

标签: c++ parallel-processing operator-overloading openmp

我正在尝试使用OpenMP

并行化以下函数中的循环
 void CEnergymulti::forcetwobody(vector<CMolecule*>  m_mols,CPnt force0,CPnt torque0)
{
 const int nmol=m_mols.size();
 vector<CMolecule*> twomols(2);
 CPnt forcetemp,torquetemp;
 twomols.clear();
 force0.zero();
 torque0.zero();
 forcetemp.zero();
 torquetemp.zero();
 #pragma omp parallel for reduction(+:force0,torque0) private(twomols)
 for(int j=1;j<nmol;j++)
       { twomols.push_back(m_mols[0]);
         twomols.push_back(m_mols[j]);
         CMolecule::polarize_mutual(twomols,false, 1000);
         twomols[0]->computeMol_Force_and_Torque(forcetemp,torquetemp);
         force0+=forcetemp;
         torque0+=torquetemp;
         forcetemp.zero();
         torquetemp.zero();
         twomols.clear();
        }
     REAL converter=COUL_K*IKbT;
     force0*=converter;
     torque0*=converter;
     return;
     }

编译代码时,它会显示以下消息:

EnergyD_multi.cpp: In static member function ‘static void
CEnergymulti::forcetwobody(std::vector<CMolecule*,
std::allocator<CMolecule*> >, CPnt, CPnt)’: EnergyD_multi.cpp:226:
error: ‘torque0’ has invalid type for ‘reduction’
EnergyD_multi.cpp:226: error: ‘force0’ has invalid type for
‘reduction’

我理解变量'force0'和'torque0'既不是双重或整数类型的数据,而是类型'CPnt',这是一个定义为表示空间中三维向量的类。对于类'CPnt',运算符'+'和' - '已经由运算符重载定义。所以我的问题是:OpenMP的减少是否真的无法处理这样的重载运算符?有没有其他方法可以将此循环与OpenMP并行化而不减少'force0'和'torque0'的每个组件?

非常感谢。

2 个答案:

答案 0 :(得分:7)

OpenMP减少无法处理这样的重载运算符。但是,还有另一种选择。重写OpenMP减少的一种方法是使用nowaitatomic参数。 http://bisqwit.iki.fi/story/howto/openmp/#ReductionClause 这和正常方式一样快。

如果将atomic替换为critical,则可以使用更复杂的重载运算符。这不如使用atomic那么快,但在我的经验中它仍然有效。

我这样做了所以我可以使用同时操作4或8个浮点数的运算符(使用SEE或AVX)。 reduction with OpenMP with SSE/AVX

编辑:我改变了你的代码,以反映我认为你想做的事情。

void CEnergymulti::forcetwobody(vector<CMolecule*>  m_mols,CPnt force0,CPnt torque0)
{
    const int nmol=m_mols.size();
    force0.zero();
    torque0.zero();
    #pragma omp parallel
    {
        CPnt force0_private;
        CPnt torque0_private; 
        force0_private.clear();
        torque0_private.clear();
        #pragma omp for nowait
        for(int j=1;j<nmol;j++)
        { 
            CPnt forcetemp,torquetemp;
            forcetemp.zero();
            torquetemp.zero();
            vector<CMolecule*> twomols(2);
            twomols.clear();
            twomols.push_back(m_mols[0]);
            twomols.push_back(m_mols[j]);
            CMolecule::polarize_mutual(twomols,false, 1000);
            twomols[0]->computeMol_Force_and_Torque(forcetemp,torquetemp);
            force0_private+=forcetemp;
            torque0_private+=torquetemp;
        }
        #pragma omp critical 
        {
           force0 += force0_private;
           torque0 += torque0_private;
        }

    }
    REAL converter=COUL_K*IKbT;
    force0*=converter;
    torque0*=converter;
    return;
}

答案 1 :(得分:2)

这几天,您还可以使用declare reduction指令(OpenMP 4.0+);例如

#pragma omp declare reduction(mysum:CPnt:omp_out += omp_in) initializer(omp_priv.zero())
#pragma omp parallel for reduction(mysum:force0,torque0) private(twomols)
for(int j=1;j<nmol;j++)
...