【问题标题】:Avoiding conflicts among threads in openmp避免openmp中线程之间的冲突
【发布时间】:2019-02-08 12:13:46
【问题描述】:

我刚开始学习 openmp 编程,但被困在一段代码中,该代码试图并行化程序以计算 pi。我无法理解这一行在程序中的作用以及后续评论的含义。

  if (id == 0) nthreads = nthrds; //Only one thread should copy the number of threads to the global value to make sure multiple threads writing to the same address don’t conflict.

整个代码是:

#include<omp.h>
#include<stdio.h>
#define NUM_THREADS 2

static long num_steps = 100000;
double step;

int main ()
{
   int i, nthreads;
   double pi, sum[NUM_THREADS];
   step = 1.0/(double) num_steps;

   omp_set_num_threads(NUM_THREADS);
   double time1 = omp_get_wtime();
   #pragma omp parallel
   {
       int i, id,nthrds;
       double x;
       id = omp_get_thread_num();
       nthrds = omp_get_num_threads();
       if (id == 0) nthreads = nthrds; //Only one thread should copy 
       the number of threads to the global value to make sure multiple 
       threads writing to the same address don’t conflict.

       for (i=id, sum[id]=0.0;i< num_steps; i=i+nthrds){
             x = (i+0.5)*step;
             sum[id] += 4.0/(1.0+x*x);
       }
   }
   double time2 = omp_get_wtime();

   for(i=0, pi=0.0;i<nthreads;i++)pi += sum[i] * step;
   printf("%lf\n",pi);
   printf("%lf\n",(time2-time1));

}

我尝试在没有 if 语句的情况下运行,但它给出了 pi 0 的值,但在其他情况下运行正确(给出 3.141593)。当我尝试分配 nthreads 等于全局外部的线程总数(即 2)时,它仍然给出了正确的 pi 值。谁能解释一下输出有什么不同?

谢谢!!

【问题讨论】:

    标签: openmp


    【解决方案1】:

    当您尝试分配 nthreads 等于全局外部的线程总数(即 2)时,它仍然给出了正确的 pi 值,因为您从计算机询问的线程数已提供给您(即在您的情况是 2) 但是如果你要求 100 万个线程,计算机可能不会给你这么多线程。所以要知道给你分配了多少线程,你需要写这段代码。

        if (id == 0) nthreads = nthrds;
    

    【讨论】:

      【解决方案2】:

      需要为最终循环中的求和步骤设置变量nthreads

      for(i=0, pi=0.0;i<nthreads;i++)pi += sum[i] * step;
      

      删除分配将打破这个循环。 让我尝试重新表述为什么你不能简单地做的评论

      nthreads = nthrds;
      

      如果您在没有任何保护的情况下从多个线程写入共享内存位置,则该值可能是错误的。但是,通常使用atomic 作为保护。在这种情况下,#pragma omp single nowait 会更合适。我动态地编写这个变量而不是仅仅使用NUM_THREADS 背后的想法是你可能并不总是保证它。

      无论如何。这个教程问题很大。它尝试使用原始原语而不是使用适当的惯用高级工具来教授 OpenMP。这会导致lotsconfusion。我认为这是教授 OpenMP 的一种不好的方法,尤其是如果您没有坚持到底。​​p>

      教程后面实际上给出了正确的方法(我做了一些现代化):

      double sum = 0.0;
      int step = 1.0/(double) num_steps;
      omp_set_num_threads(NUM_THREADS);
      #pragma omp parallel for reduction(+:sum)
      for (int i=0; i < num_steps; i++) {
          double x = (i+0.5)*step;
          sum = sum + 4.0/(1.0+x*x);
      }
      double pi = step * sum;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-10-09
        • 1970-01-01
        • 1970-01-01
        • 2019-02-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多