循环C ++中的分段错误Openmp

Posted

技术标签:

【中文标题】循环C ++中的分段错误Openmp【英文标题】:Segmentation fault Openmp in loop C++ 【发布时间】:2017-11-29 21:30:46 【问题描述】:

我正在尝试在 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); 
        
    

这是 calculateAstoidMov 是:

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; 

我应该如何并行化计算力的循环? 我希望它很清楚......

【问题讨论】:

forces的单个实例被所有线程共享,可以被多个线程写入。 @1201ProgramAlarm ,但问题是该行是所有逻辑所在的地方。如果我在线程访问该变量时加锁,则根本不会有有用的并行化 【参考方案1】:

有两种方法可以解决这个问题。

1。双缓冲:

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

取决于 invertForze() 所做的事情,这也可能使您受益于使整个过程顺序独立。

2。模拟岛:

将您的小行星场分解为相互作用的小行星的子场,并在每个岛的基础上并行化,而不是在每个小行星的基础上。

这是大多数现代物理引擎使用的方法,因为它们使用的假设是岛屿往往一帧一帧地保持不变,但与简单的双缓冲解决方案相比,实施起来要复杂得多。

【讨论】:

我得到了双缓冲,但是,为了控制数组,应该是这样的?:#pragma omp parallel num_threads(4) public(asteroidsRead) private(asteroidsWrite) 反转力很简单,只要改变力的符号。 PD:我没有接近模拟岛【参考方案2】:

问题是你同时从不同的线程写入力向量。您可以将其声明移至内部 for 循环,因此并发不会成为问题。我还假设,当您不计算 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);
    

【讨论】:

以上是关于循环C ++中的分段错误Openmp的主要内容,如果未能解决你的问题,请参考以下文章

c ++分段错误将指针传递给函数

需要帮助查找 C 程序中的分段错误

来自 for 循环的分段错误

在opencv c ++中查找图像卷积时出现分段错误(核心转储)错误

由于 C 中的内存不足导致的分段错误

C 中 Trie 实现中的分段错误