我目前正在学习openMP基础知识,所以我选择了一个简单的练习并开始解决:我得到了一个接近Pi值的串行程序的实现,我被要求给它并行实现。
连续程序:
static long num_steps = 100000;
double step;
void main ()
{
int i;
double x, pi, sum = 0.0;
step = 1.0/(double) num_steps;
for (i=0;i< num_steps; i++){
x = (i+0.5)*step;
sum = sum + 4.0/(1.0+x*x);
}
pi = step * sum;
}
它在0到1的间隔内计算4.0 /(1 +x²)dx积分的近似值。
本教程使用的是增量方法,在每个步骤中都给出了一些块,所以现在,我可以使用带有一些运行时函数的并行构造。
对我来说,显而易见的事情就是划分和执行部分求和。这是我的解决方案:
int main()
{
const long num_steps = 100000;
double step;
double pi, sum = 0.0;
step = 1.0/(double) num_steps;
int num_steps_perthread = num_steps/4;
double start_time = omp_get_wtime();
#pragma omp parallel num_threads(4)
{
double x,partial_sum = 0.0;
int init = num_steps_perthread * omp_get_thread_num();
std::cout << init <<"\n";
for (int i = init;i< init+num_steps_perthread; i++){
x = (i+0.5)*step;
partial_sum += 4.0/(1.0+x*x);
}
sum += partial_sum;// this line data race
}
pi = step * sum;
double time = omp_get_wtime() - start_time;
std::cout << pi << " computed in " << time;
return 0;
}
所以在提问之前,这是我对openMP并行构造的假设(如果我错了,请纠正我):
当我运行程序时,我得到预期的输出,但通常(IMO)我不应该,因为我已经写了一个数据竞赛(它在代码中表示)。变量sum由多个线程写入。
我认为一种可能的情况是,例如,线程号2写入sum并更新它的值,但是在处理器更新内存位置的整个层次结构(高速缓存和RAM的级别)之前另一个线程(假设线程4) )获取旧值并使用它的部分总和更新它。所以我们不会有一个补充,而是覆盖。
1)sum = 0 2)线程2添加它的partial_sum。让我们说+2。 sum = 2但其他内存位置仍保留旧值。 3)线程4选择旧值并添加到它。 4)用线程2更新和的所有存储器位置是结果。 5)更新线程4的结果会覆盖该值。
问题:
注意:我知道openMP中的工作共享,只是本教程的方法强加了这种解决方案。