【问题标题】:Difference between two methods for OpenMP parallelOpenMP并行的两种方法之间的区别
【发布时间】:2021-06-11 03:51:11
【问题描述】:

我只想通过 OpenMP 的汇总来评估函数的集成,方法是使用一个数组来保存每个步骤中计算的每个值 > 取所有值的总和;并在没有数组的情况下取和。

代码是:

double f(double x)
{
    return sin(x)*sin(x)/(x*x+1);
}

方法一

    long i = 0;
    const long NUM_STEP = 100000;
    double sum[NUM_STEP];
    double from = 0.0, to = 1.0;
    double step = (to - from)/NUM_STEP;
    double result = 0;

    #pragma omp parallel for shared(sum) num_threads(4)
    for(i=0; i<NUM_STEP; i++)
        sum[i] = step*f(from+i*step);
    for(i=0; i<NUM_STEP; i++)
        result += sum[i];
    printf("%lf", result);

方法 2

    long i = 0;
    const long NUM_STEP = 100000;
    double from = 0.0, to = 1.0;
    double step = (to - from)/NUM_STEP;
    double result = 0;

    #pragma omp parallel for shared(result) num_threads(4)
    for(i=0; i<NUM_STEP; i++)
        result += step*f(from+i*step);
    printf("%lf", result);

但结果相差太大。方法 1 给出了一个稳定的值,但方法 2 给出了一个可变值。这是一个例子:

方法一:0.178446

方法二:0.158738

METHOD 1 的值为真(由另一个工具检查)。

【问题讨论】:

    标签: c multithreading parallel-processing openmp race-condition


    【解决方案1】:

    TL;DR第一种方法没有竞态条件,而第二种方法有。

    第一种方法没有竞争条件,而第二种方法有。即在第一种方法中:

    #pragma omp parallel for shared(sum) num_threads(4)
    for(i=0; i<NUM_STEP; i++)
        sum[i] = step*f(from+i*step);
    for(i=0; i<NUM_STEP; i++)
        result += sum[i];
    

    每个线程将step*f(from+i*step); 操作的结果保存在数组sum[i] 的不同位置。之后 master 线程,依次减少保存在数组sum 上的值,即:

    for(i=0; i<NUM_STEP; i++)
        result += sum[i];
    

    实际上,您可以在此版本上进行一些改进;而不是分配与NUM_STEP的数量相同大小的数组sum,您可以分配与线程数相同的大小,每个线程将保存在与其ID相等的位置,即:

    int total_threads = 4;
    double sum[total_threads];
    #pragma omp parallel num_threads(total_threads)
    {
      int thread_id = omp_get_thread_num();
      for(i=0; i<NUM_STEP; i++)
          sum[thread_id] += step*f(from+i*step);
      for(i=0; i< total_threads; i++)
          result += sum[i];
    }
    

    尽管如此,最好的方法是实际修复第二种方法。

    在第二种方法中,变量result的更新有一个race-condition

    #pragma omp parallel for shared(result) num_threads(4)
    for(i=0; i<NUM_STEP; i++)
        result += step*f(from+i*step);
    

    因为result 变量正在由多个线程以非线程安全的方式同时更新。

    要解决这个竞态条件,您需要使用reduction 子句:

    #pragma omp parallel for reduction(+:result) num_threads(4)
    for(i=0; i<NUM_STEP; i++)
        result += step*f(from+i*step);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-29
      • 1970-01-01
      • 2015-03-18
      相关资源
      最近更新 更多