Преобразование c последовательно в проблемы OpenMP

Я работаю над назначением n-body, которое преобразует последовательную программу в параллельную, используя OpenMP. У меня есть функция ниже, которая прекрасно работает с выключенным OpenMP, но в противном случае выдает неправильный результат. У меня есть блокировка вокруг единственных переменных, обновляемых внутри цикла, которые не объявлены внутри цикла. Я давно смотрю на это и не уверен, что делаю неправильно. Любые советы будут с благодарностью.

void update() {
  int i, j;
  Body *tmp;

  omp_lock_t lock;
  omp_init_lock(&lock);

  for (i=0; i<numBodies; i++) {
    double x = bodies[i].x;
    double y = bodies[i].y;
    double vx = bodies[i].vx;
    double vy = bodies[i].vy;
    double ax = 0;
    double ay = 0;

    #pragma omp parallel for num_threads(4)
    for (j=0; j<numBodies; j++) {
      double r, mass, dx, dy, r_squared, acceleration;

      if (j==i) continue;
      dx = bodies[j].x - x;
      dy = bodies[j].y - y;
      mass = bodies[j].mass;
      r_squared = dx*dx + dy*dy;
      if (r_squared != 0) {
        r = sqrt(r_squared);
        if (r != 0) {
          acceleration = K*mass/(r_squared);
          omp_set_lock(&lock);
          ax += acceleration*dx/r;
          ay += acceleration*dy/r;
          omp_unset_lock(&lock);
        }
      }
    }
    x += vx;
    y += vy;
    if (x>=x_max || x<x_min) x=x+(ceil((x_max-x)/univ_x)-1)*univ_x;
    if (y>=y_max || y<y_min) y=y+(ceil((y_max-y)/univ_y)-1)*univ_y;
    vx += ax;
    vy += ay;
    assert(!(isnan(x) || isnan(y)));
    assert(!(isnan(vx) || isnan(vy)));
    bodies_new[i].x = x;
    bodies_new[i].y = y;
    bodies_new[i].vx = vx;
    bodies_new[i].vy = vy;
  }
  tmp = bodies;
  bodies = bodies_new;
  bodies_new = tmp;
  omp_destroy_lock(&lock);
}

1 ответ

Переместил прагму во внешний цикл, убрал сокращение и добавил I и j как частные.

Другие вопросы по тегам