我正在尝试在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;
}
我应该如何并行化计算力的循环? 我希望很清楚......
答案 0 :(得分:1)
有两种方法可以解决这个问题。
维护两个小行星列表,一个是你读过的,一个是你写的。许多线程可以安全地从同一个小行星中读取,并且保证每个线程都写入其他人无法访问的内存区域。
对invertForze()
所做的事情进行了延伸,这也可能使您获得使整个流程顺序独立的好处。
将小行星场分解为相互作用的小行星的子场,并按岛屿进行并列化,而不是按小行星进行。
这是大多数现代物理引擎使用的方法,因为它们使用了岛屿往往保持相同帧数的假设,但与简单的双缓冲解决方案相比,它实施起来要复杂得多。 / p>
答案 1 :(得分:0)
问题是您是否同时从不同的线程写入力矢量。您可以将它的声明移动到内部for循环,因此并发性不会成为问题。我还假设,当你不计算invertForze
时,你不应该致电forces
。
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);
}
}