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在所有并行线程中求和(副本),因此您需要在并行段的末尾应用归约运算符以将所有这些组合回单个值。此外,变量ixyz需要为每个并行线程提供单独的实例——您不希望线程使用相同的实例!要指定所有这些,#pragma循环顶部的指令应该是:

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

此外,它的范围是for循环,所以你不需要做任何其他事情;循环退出后将自动同步线程。(而且你需要同步来count包含来自所有线程的所有增量!)特别是,你的taskbarrierpragma 是没有意义的,因为此时你只回到一个线程——而且,此外,没有必要放那个并行任务中的单个计算。

在这些情况下,gabe 提出了一个问题,即系统随机数生成器可能很慢和/或随机性差。您可能需要调查系统上的细节,并在每个线程中为其提供一个新的随机种子,或者根据您的发现使用不同的随机数生成器。

除此之外,它看起来相当合理。您对该算法无能为力,因为它很短且易于并行化。

于 2010-03-02T10:12:08.927 回答