4

OpenMPのスレッドを使用して以下のコードの並列バージョンを実装したいのですが、これを行うためのより良い方法はありますか?

/* Program to compute Pi using Monte Carlo methods */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>
#define SEED 35791246

int main(int argc, char* argv)
{
   int niter=0;
   double x,y;
   int i,count=0; /* # of points in the 1st quadrant of unit circle */
   double z;
   double pi;
   clock_t end_time, start_time; 


   printf("Enter the number of iterations used to estimate pi: ");
   scanf("%d",&niter);

   start_time = clock(); 
   /* initialize random numbers */
   srand(SEED);
   count=0;

 #pragma omp parallel for
      for ( i=0; i<niter; i++) {
      x = (double)rand()/RAND_MAX;
      y = (double)rand()/RAND_MAX;
      z = x*x+y*y;
      if (z<=1) count++;
    }  
#pragma omp task
   pi=(double)count/niter*4;
#pragma omp barrier

   end_time = clock();

   printf("# of trials= %d , estimate of pi is %g, time= %f \n",niter,pi, difftime(end_time, start_time));

   return 0;
}
4

2 に答える 2

2

このrand関数をここで使用することはお勧めできません。スレッドセーフではなく、スレッドが重複した値を取得する(あまりランダムではない)か、ロックがあり、MPバージョンがシングルスレッドバージョンよりも遅くなります。

複数のスレッドから同時に使用できる別の乱数ジェネレーターを見つけることをお勧めします。

于 2010-03-02T10:09:56.373 に答える
2

いくつかのOpenMPバグを修正することで改善できる可能性があります。まず、すべての並列スレッドで合計(のコピー)countを行うため、並列セグメントの最後に縮小演算子を適用して、それらすべてを1つの値に戻す必要があります。また、変数、、、iおよびは、x並列スレッドごとに個別のインスタンスを持つ必要があります。同じスレッドを使用するスレッドは必要ありません。そのすべてを指定するには、ループの先頭にあるディレクティブは次のようになります。yz#pragma

#pragma omp parallel for private(i, x, y, z) reduction(+:count)

また、その範囲はforループであるため、他に何もする必要はありません。ループが終了した後、スレッドの同期が自動的に行われます。count(そして、すべてのスレッドからのすべての増分を含めるには、その同期が必要です!)特に、その時点で1つのスレッドに戻っているため、プラグマtaskとプラグマは無意味です。さらに、それを配置しても意味がありません。barrier並列タスクでの単一の計算。

そして、これらの場合、システムの乱数ジェネレーターの速度の低下やランダム性の低下について、gabeが提起した問題があります。システムでその詳細を調査し、各スレッドで新しい乱数シードを与えるか、見つけたものに応じて異なる乱数ジェネレーターを使用することをお勧めします。

それに加えて、それはかなり合理的に見えます。このアルゴリズムは短く、簡単に並列化できるため、他にできることはほとんどありません。

于 2010-03-02T10:12:08.927 に答える