循环C 的分割故障OpenMP

Segmentation fault Openmp in loop C++

本文关键字:故障 OpenMP 分割 循环      更新时间:2023-10-16

我正在尝试在C 中并行化for循环。这个想法是给定小行星阵列,我计算了小行星之间产生的重力力。每个小行星都有其质量和位置。

我想并行化此循环,但是问题是当线程想要访问其他线程用于计算力的任何小行星时,存在分段故障。

这是我的代码:

    //For each asteroid calculate forzes acting 
    for(unsigned long j=0; j<asteroids.size(); j++){
        vector<double>forces(2);
        {
        #pragma omp parallel num_threads(4)
        #pragma omp for
        //I start in x instead of 0 to avoid redundance calculation
        for(unsigned long x=j; x <asteroids.size(); x++){
            //Avoid calculations on itself
            if(asteroids[j].getX() != asteroids[x].getX() && asteroids[j].getY() != asteroids[x].getY()){
                forces = asteroids[j].calculateAsteroidMov(asteroids[x], gravity, dmin);
            }
            asteroids[x].invertForze(forces[0], forces[1]);
        }
        }
        for(unsigned long j=0; j<asteroids.size(); j++){
            asteroids[j].updatePosition(t, width, height); 
        }
    }

这是colculatostoidmov是:

std::vector<double> Asteroid::calculateAsteroidMov(Asteroid neighbour, double gravity, double dmin){
    //Distance between 
    double xdist = x - neighbour.getX();
    double ydist = y - neighbour.getY();
    double dist = sqrt( xdist*xdist + ydist*ydist );
    double xforze = 0; 
    double yforze = 0;
    if(dist > dmin){
        double slope = ydist / xdist;
        if(slope > 1 || slope < -1){
            slope -= trunc(slope);
        }
        double alfa = atan(slope);
        xforze = ((gravity * mass * neighbour.getMass()) / (dist*dist));
        yforze = ((gravity * mass * neighbour.getMass()) / (dist*dist));
        if(xforze > 200){
            xforze = 200;
        }else if(yforze > 200){
            yforze = 200;
        }
        xforze *= cos(alfa);
        yforze *= sin(alfa);
        sumxforze += xforze;
        sumyforze += yforze;
    }
    std::vector<double> forces = {xforze, yforze};
    return forces;
}

和updatePosition()

void Asteroid::updatePosition(double t,  double width, double height){
    //Spped update
    vx += (sumxforze/mass) * t;
    vy += (sumyforze/mass) * t;
    //Position update
    x += vx * t;
    y += vy * t; 
}

我应该如何平行计算力的循环?我希望这很清楚...

有两种解决此问题的方法。

1。双重缓冲:

维护两个小行星列表,一份是您从中读取的小行星,一份是您写的。许多线程可以安全地从同一个小行星中读取,并且您可以确保每个线程都写入其他人无法访问的内存区域。

invertForze()的作用,这也可能给您带来整个流程订单独立的好处。

2。模拟岛:

将您的小行星场分解为相互作用的小行星的子场,并以人均为基础,而不是以每asterotoid为基础。

这是大多数现代物理发动机使用的方法,因为它们使用这样的假设,即岛屿倾向于在框架之后保持相同的框架,但是与简单的双缓冲解决方案相比,放置要复杂得多。<<<<<<<<<<<<<</p>

问题是您同时从不同线程编写力向量。您可以将其声明移至内部循环,因此并发不会是问题。我还假设,当您不计算forces时,您不应该致电invertForze

for(unsigned long j=0; j<asteroids.size(); j++){
    {
        #pragma omp parallel num_threads(4)
        #pragma omp for
        //I start in x instead of 0 to avoid redundance calculation
        for(unsigned long x=j; x <asteroids.size(); x++){
            //Avoid calculations on itself
            if(asteroids[j].getX() != asteroids[x].getX() && asteroids[j].getY() != asteroids[x].getY()){            
                vector<double> forces = asteroids[j].calculateAsteroidMov(asteroids[x], gravity, dmin);
                asteroids[x].invertForze(forces[0], forces[1]);
            }
        }
    }
    for(unsigned long j=0; j<asteroids.size(); j++){
        asteroids[j].updatePosition(t, width, height);
    }
}