You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用OpenMP Task并行化Pi计算程序后结果为0的问题排查

OpenMP递归计算Pi并行程序错误排查

问题描述

我尝试用OpenMP task将递归计算Pi的串行程序改为并行版本,串行程序能得到正确的Pi值(3.141593),但并行版本运行结果Pi为0.000000,无法得到正确结果。

串行代码

#include <omp.h>
#include <stdio.h>
static long num_steps = 1024*1024*1024;
#define MIN_BLK  1024*1024*256

double pi_comp(int Nstart,int Nfinish,double step)
{  int i,iblk;
double x, sum = 0.0,sum1, sum2;
if (Nfinish-Nstart < MIN_BLK){
  for (i=Nstart;i< Nfinish; i++){
     x = (i+0.5)*step;
     sum = sum + 4.0/(1.0+x*x); 
  }
}
else{
  iblk = Nfinish-Nstart;
  sum1 = pi_comp(Nstart,         Nfinish-iblk/2,step);
  sum2 = pi_comp(Nfinish-iblk/2, Nfinish,       step);
  sum = sum1 + sum2;
}return sum;
}
int main ()
{
int i;
double step, pi, sum;
double init_time, final_time;
step = 1.0/(double) num_steps;

init_time = omp_get_wtime();
sum = pi_comp(0,num_steps,step);
pi = step * sum;
final_time = omp_get_wtime() - init_time;
printf(" for %ld steps pi = %f in %f secs\n",num_steps,pi,final_time);

}  

并行代码(错误版本)

#include <omp.h>
#include <stdio.h>
static long num_steps = 1024*1024*1024;
#define MIN_BLK  1024*1024*256

double pi_comp(int Nstart,int Nfinish,double step)
{  int i,iblk;
double x, sum = 0.0,sum1, sum2;
if (Nfinish-Nstart < MIN_BLK){
  for (i=Nstart;i< Nfinish; i++){
     x = (i+0.5)*step;
     sum = sum + 4.0/(1.0+x*x); 
  }
}
else{
  iblk = Nfinish-Nstart;
  #pragma omp task firstprivate(sum1)
  sum1 = pi_comp(Nstart,Nfinish-iblk/2,step);
  #pragma omp task firstprivate(sum2)
  sum2 = pi_comp(Nfinish-iblk/2, Nfinish,step);
  sum = sum1 + sum2;
}return sum;
}
int main ()
{
int i;
double step, pi, sum;
double init_time, final_time;
step = 1.0/(double) num_steps;

init_time = omp_get_wtime();
#pragma omp parallel
{
#pragma omp single
sum = pi_comp(0,num_steps,step);
}

pi = step * sum;
final_time = omp_get_wtime() - init_time;
printf(" for %ld steps pi = %f in %f secs\n",num_steps,pi,final_time);

}  

运行输出

g++ -fopenmp  -c pi_recur_omp.cpp
g++ -fopenmp  -o pi_recur_omp pi_recur_omp.o -lm
./pi_recur 
 for 1073741824 steps pi = 3.141593 in 4.562793 secs
./pi_recur_omp 
 for 1073741824 steps pi = 0.000000 in 2.990318 secs

错误原因分析

核心问题是没有等待异步任务完成就读取计算结果:

  • OpenMP task是异步执行的,创建sum1和sum2的任务后,当前线程会直接执行sum = sum1 + sum2,但此时两个任务还未完成,sum1和sum2仍为初始的0.0,导致最终sum为0,Pi计算结果自然是0。
  • 额外问题:firstprivate(sum1)和firstprivate(sum2)是错误的,sum1、sum2是当前函数的局部变量,firstprivate会创建它们的私有副本,任务中赋值的是副本而非原变量,原变量依然保持0值。

修正后的并行代码

#include <omp.h>
#include <stdio.h>
static long num_steps = 1024*1024*1024;
#define MIN_BLK  1024*1024*256

double pi_comp(int Nstart,int Nfinish,double step)
{  
    int i, iblk;
    double x, sum = 0.0, sum1, sum2;
    if (Nfinish - Nstart < MIN_BLK) {
        for (i = Nstart; i < Nfinish; i++) {
            x = (i + 0.5) * step;
            sum += 4.0 / (1.0 + x*x); 
        }
    } else {
        iblk = Nfinish - Nstart;
        // 创建任务,默认shared属性,直接修改原变量
        #pragma omp task shared(sum1)
        sum1 = pi_comp(Nstart, Nfinish - iblk/2, step);
        #pragma omp task shared(sum2)
        sum2 = pi_comp(Nfinish - iblk/2, Nfinish, step);
        // 等待所有任务完成后再计算总和
        #pragma omp taskwait
        sum = sum1 + sum2;
    }
    return sum;
}

int main ()
{
    int i;
    double step, pi, sum;
    double init_time, final_time;
    step = 1.0 / (double) num_steps;

    init_time = omp_get_wtime();
    #pragma omp parallel
    {
        #pragma omp single
        sum = pi_comp(0, num_steps, step);
    }

    pi = step * sum;
    final_time = omp_get_wtime() - init_time;
    printf(" for %ld steps pi = %f in %f secs\n", num_steps, pi, final_time);
}  

修正说明

  1. 添加#pragma omp taskwait:强制当前线程等待所有已创建的任务完成,确保sum1和sum2已经被正确赋值后再计算总和。
  2. 移除firstprivate:改用默认的shared属性,让任务直接修改原函数的sum1和sum2变量,确保赋值结果能被主线程读取。

内容的提问来源于stack exchange,提问作者HotbrewGX

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 12:40:35