1

ループスレッドを安全にするために、ロックとクリティカルセクションをいじっています。コードは次のとおりです。

#pragma omp parallel for num_threads(4) private(k, f_part_k, len, len_3, mg, fact)
for (k = part+1; k < n; k++) {
  /* Compute force on part due to k */
  f_part_k[X] = curr[part].s[X] - curr[k].s[X];
  f_part_k[Y] = curr[part].s[Y] - curr[k].s[Y];
  len = sqrt(f_part_k[X]*f_part_k[X] + f_part_k[Y]*f_part_k[Y]);
  len_3 = len*len*len;
  mg = -G*curr[part].m*curr[k].m;
  fact = mg/len_3;
  f_part_k[X] *= fact;
  f_part_k[Y] *= fact;

  /* Add force in to total forces */
  omp_set_lock(&(locks[k]));
  //#pragma omp critical
  {
      forces[part][X] += f_part_k[X];
      forces[part][Y] += f_part_k[Y];
      forces[k][X] -= f_part_k[X];
      forces[k][Y] -= f_part_k[Y];
  }
  omp_unset_lock(&(locks[k]));
}

for (i = 0; i < n; i++)
    omp_destroy_lock(&(locks[i]));
} 

コメント アウトされたクリティカル ディレクティブのみを使用すると、結果は良好です。つまり、シーケンシャル バージョンの結果と一致します。ただし、コードに示されているようにロックを使用すると、結果は大きく異なります。このロック アプローチを使用する私の理解では、force 配列への書き込みアクセスは安全でなければならないため、ロックの概念を誤解していると思います。正しい方向に私を向けることができますか?

4

1 に答える 1

4

あなたのコードの問題は、次の競合状態だと思います。

omp_set_lock(&(locks[k]));
{
    forces[part][X] += f_part_k[X]; // Race condition for different k
    forces[part][Y] += f_part_k[Y]; // Race condition for different k
    forces[k][X] -= f_part_k[X]; 
    forces[k][Y] -= f_part_k[Y]; 
}
omp_unset_lock(&(locks[k]));

実際、 の異なる値に対してk、複数のスレッドが および に書き込もうforces[part][X]としforces[part][Y]ます。さらに、各スレッドが独自の を更新するためforces[k][X]、 andへのアクセスを明示的に同期する必要はないと思います。forces[k][Y]k

適切なセマンティックを提供するさまざまな同期構造を試してみたい場合は、次を試すことができます。

原子レベルの同期

#pragma omp atomic
forces[part][X] += f_part_k[X];
#pragma omp atomic
forces[part][Y] += f_part_k[Y];

forces[k][X] -= f_part_k[X]; 
forces[k][Y] -= f_part_k[Y]; 

明示的ロック

omp_set_lock(&lock);
{
  forces[part][X] += f_part_k[X];
  forces[part][Y] += f_part_k[Y];
}
omp_unset_lock(&lock);

forces[k][X] -= f_part_k[X]; 
forces[k][Y] -= f_part_k[Y];

名前付きクリティカル セクション

#pragma omp critical(PART)
{
  forces[part][X] += f_part_k[X];
  forces[part][Y] += f_part_k[Y];
}
forces[k][X] -= f_part_k[X]; 
forces[k][Y] -= f_part_k[Y]; 

ここcriticalでandatomic構文の定義(セクション 2.8.2 および 2.8.5) を読み、例A.19.1cA.22.*、およびA.45.1cを確認することをお勧めします。


とはいえ、あなたが提示した場合、私は次のことを試します:

float fredx = 0.0f;
float fredy = 0.0f;
#pragma omp parallel for private(k, f_part_k, len, len_3, mg, fact) reduction(+:fredx,fredy)
for (k = part+1; k < n; k++) {
  /* Compute force on part due to k */
  f_part_k[X] = curr[part].s[X] - curr[k].s[X];
  f_part_k[Y] = curr[part].s[Y] - curr[k].s[Y];
  len = sqrt(f_part_k[X]*f_part_k[X] + f_part_k[Y]*f_part_k[Y]);
  len_3 = len*len*len;
  mg = -G*curr[part].m*curr[k].m;
  fact = mg/len_3;
  f_part_k[X] *= fact;
  f_part_k[Y] *= fact;

  /* Add force in to total forces */
  fredx += f_part_k[X];
  fredy += f_part_k[Y];

  forces[k][X] -= f_part_k[X];
  forces[k][Y] -= f_part_k[Y];            
}

forces[part][X] += fredx;
forces[part][Y] += fredy;

明示的な同期を避けるため。

于 2013-06-10T08:40:15.970 に答える