越来越多的OMP线程会改变输出值

时间:2017-02-18 12:48:06

标签: c++ parallel-processing openmp

我附加了一个代码,当使用OMP进行并行化时会产生不同的输出。 这并不意味着发生。

我相信我已经涵盖了与'私人'变量和'减少'条款相关的通常常见的陷阱。

我附加了全局代码中的相关函数。感激地接受任何智慧。

编辑*我怀疑问题出在我的arma :: cross乘以从MatIplusIplus的第i次迭代和MatPtJplusJplus的第j次迭代中得到的列向量? *

double calcul( arma::mat MatPt, int iS, int THREADS){ 

int i,j, count = 1;
double Wr = 0 , Omega;

arma::mat MatJplusIplus ( 3 , iS ) ;
arma::mat MatJI ( 3 , iS ) ;
arma::mat MatJplusI ( 3 , iS ) ;
arma::mat MatJIplus ( 3 , iS ) ;

arma::mat MatIplusI ( 3 , iS ) ;
arma::mat MatJplusJ ( 3 , iS ) ;

#pragma omp parallel for private(j) reduction(+: Wr) reduction(*: Omega)
for( i = 0 ; i < iS- (3) ; i++ ){//rethink boundaries.

    MatIplusI ( 0 , i ) = MatPt (0, i+1) - MatPt (0, i) ;
    MatIplusI ( 1 , i ) = MatPt (1, i+1) - MatPt (1, i) ;
    MatIplusI ( 2 , i ) = MatPt (2, i+1) - MatPt (2, i) ;

    for( j= i+2 ; j < iS-(1) ; j++ ){

        MatJIplus  ( 0, j ) = MatPt (0, j) - MatPt (0, i+1) ;
        MatJIplus  ( 1, j ) = MatPt (1, j) - MatPt (1, i+1) ;
        MatJIplus  ( 2, j ) = MatPt (2, j) - MatPt (2, i+1) ;

        MatJplusIplus  ( 0, j ) = MatPt (0, j+1) - MatPt (0, i+1) ;
        MatJplusIplus  ( 1, j ) = MatPt (1, j+1) - MatPt (1, i+1) ;
        MatJplusIplus  ( 2, j ) = MatPt (2, j+1) - MatPt (2, i+1) ;

        MatJI  ( 0, j ) = MatPt (0, j) - MatPt (0, i) ;
        MatJI  ( 1, j ) = MatPt (1, j) - MatPt (1, i) ;
        MatJI  ( 2, j ) = MatPt (2, j) - MatPt (2, i) ;

        MatJplusI  ( 0, j ) = MatPt (0, j+1) - MatPt (0, i) ;
        MatJplusI  ( 1, j ) = MatPt (1, j+1) - MatPt (1, i) ;
        MatJplusI  ( 2, j ) = MatPt (2, j+1) - MatPt (2, i) ;

        arma::vec n1 = arma::cross( MatJI.col(j) , MatJplusI.col(j) ) ;
        arma::vec n2 = arma::cross( MatJplusI.col(j) , MatJplusIplus.col(j) ) ;
        arma::vec n3 = arma::cross( MatJplusIplus.col(j) , MatJIplus.col(j) ) ;
        arma::vec n4 = arma::cross( MatJIplus.col(j) , MatJI.col(j) ) ;

       //normalise vectors
        arma::vec N1 =  normalise(n1) ;
        arma::vec N2 =  normalise(n2) ;
        arma::vec N3 =  normalise(n3) ;
        arma::vec N4 =  normalise(n4) ;

        //take dot product
        const double ndot1 = arma:: dot ( N1 , N2 ) ;
        const double ndot2 = arma:: dot ( N2 , N3 ) ;
        const double ndot3 = arma:: dot ( N3 , N4 ) ;
        const double ndot4 = arma:: dot ( N4 , N1 ) ;

        Omega = asin(ndot1) + asin(ndot2) + asin(ndot3) + asin(ndot4) ;

        MatJplusJ( 0 , j ) = MatPt (0, j+1) - MatPt (0, j) ;
        MatJplusJ ( 1 , j ) = MatPt (1, j+1) - MatPt (1, j) ;
        MatJplusJ ( 2 , j ) = MatPt (2, j+1) - MatPt (2, j) ;

        arma::vec v = arma::cross( MatJplusJ.col(j) , MatIplusI.col(i) );

        const double wij = arma:: dot(v, MatJI.col(j) ) ;

        if (wij < 0){

             Omega *= -1/ ( 4* pi ) ;

        }

        else{

            Omega *= 1/ ( 4* pi ) ;

        }

        if (Omega != Omega){//incase something goes wrong, ignore !

            Omega = 0 ;

        }

        Wr += Omega ;

        //cout << i << " " << j << endl ;

       //PrivEnd

    }

}

Wr *= 2 ;


return Wr ;

}

非常感谢

1 个答案:

答案 0 :(得分:0)

j上的所有矩阵访问都有很多竞争条件。例如,MatJIplus ( 0, j ) = ...将由外部循环的不同迭代同时设置。

由于这些数据结构是间接的,因此您不能将它们声明为私有,您必须在工作线程本身中构造它们。由于您只使用在每个循环体内写入的矩阵部分,因此可以在循环体内声明它们。但是,为了避免在每个循环中反复重新分配这些,您可以将parallel for拆分为:

arma::mat MatIplusI ( 3 , iS ) ;
#pragma omp parallel
{
    // Matrices will be implicitly private and correctly constructed locally for each thread.
    arma::mat MatJplusIplus ( 3 , iS ) ;
    arma::mat MatJI ( 3 , iS ) ;
    arma::mat MatJplusI ( 3 , iS ) ;
    arma::mat MatJIplus ( 3 , iS ) ;
    arma::mat MatJplusJ ( 3 , iS ) ;
    #pragma omp parallel for private(j) reduction(+: Wr) private(Omega)
    {
        for( i = 0 ; i < iS- (3) ; i++ )

请注意,减少Omega绝对没有意义,它应该是私有的。

当你在每次迭代中只使用它们的列时,为完整矩阵分配内存也没什么意义。只需创建一个合适的私有数据结构来保存column(i/j)内容。