c - 无法弄清楚在c中的OPENMP程序中发生竞争条件的位置

标签 c openmp

我正在尝试将 sin(x) 从 0 积分到 pi。但是每次我跑
我得到不同输出的程序。我知道这是因为出现了竞争条件,但我无法弄清楚问题出在哪里
这是我的代码:

#include<stdio.h>
#include<stdlib.h>
#include<omp.h>
#include<math.h>
#include<time.h> 
#define NUM_THREADS 4
static long num_steps= 10000000;



float rand_generator(float a )
{
    //srand((unsigned int)time(NULL));
     return ((float)rand()/(float)(RAND_MAX)) * a;
}



int main(int argc, char *argv[])
{
   // srand((unsigned int)time(NULL));
   omp_set_num_threads(NUM_THREADS);
   float result;
   float sum[NUM_THREADS];


   float area=3.14;
   int nthreads;

#pragma omp parallel

{

     int id,nthrds;

    id=omp_get_thread_num();
    sum[id]=0.0;
    printf("%d\n",id );
    nthrds=omp_get_num_threads();
    printf("%d\n",nthrds );
    //if(id==0)nthreads=nthrds;
    for (int i = id; i < num_steps; i=i+nthrds)
    {
        //float y=rand_generator(1);
        //printf("%f\n",y );
        float x=rand_generator(3.14);
        sum[id]+=sin(x);
    }
    //printf(" sum is:  %lf\n", sum);
    //float p=(float)sum/num_steps*area;

   }


   float p=0.0;     
   for (int i = 0; i <NUM_THREADS; ++i)
   {
   p+=(sum[i]/num_steps)*area;
   }

   printf(" p is: %lf\n",p );

   }

我尝试添加 pragma atomic 但它也没有帮助。

任何帮助将不胜感激:)。

最佳答案

问题来自于rand()的使用。 rand() 不是线程安全的。原因是它对所有调用使用一个公共(public)状态,因此对竞争很敏感。 Using stdlib's rand() from multiple threads

有一个称为rand_r() 的线程安全随机生成器。状态不是将 rand 生成器状态存储在隐藏的全局变量中,而是函数的参数,并且可以在线程本地呈现。

你可以这样使用它

float rand_generator_r(float a,unsigned int *state )
{
    //srand((unsigned int)time(NULL));
     return ((float)rand_r(state)/(float)(RAND_MAX)) * a;
}

在你的并行 block 中,添加:

 unsigned int rand_state=id*time(NULL); // or whatever thread dependent seed

在你的代码调用中

   float x=rand_generator(3.14,&rand_state);

它应该可以工作。

顺便说一句,我的印象是有一个false sharing在您的代码中应该会降低性能。

 float sum[NUM_THREADS];

它被所有 线程修改并且很可能存储在单个缓存行中。 每个 存储(并且有很多存储)都会在所有其他缓存中创建一个无效,这可能会显着降低您的性能。

您应该确保这些值位于不同的缓存行中:

#define CACHE_LINE_SIZE 64
struct {
  float s;
  char padding[CACHE_LINE_SIZE - sizeof(float)];
} sum_nofalse_sharing[NUM_THREADS];

并在您的代码中,累积到 sum_nofalse_sharing[id].s

或者,在并行 block 中创建一个本地求和并将其值写入末尾的 sum[id]。

关于c - 无法弄清楚在c中的OPENMP程序中发生竞争条件的位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54973651/

相关文章:

c - 客户端断开连接后首次调用 'send' 时未收到 sigpipe

c - 使用 OpenMP 的 n 元搜索没有加速

OpenCV TBB IPP OpenMP 函数

c - 使用 open mp 的慢速稀疏矩阵 vector 积 (CSR)

c - 调用 MPF 函数时出现段错误

您可以使用指向包含结构的指针来修改嵌套结构的值吗?

c - 将结构插入动态数组

c++ - g++ : error: libgomp. 规范:没有那个文件或目录

c - 如何将 python3 c api 用于命令行驱动的应用程序?

C++ 循环和 scanf 验证字母表、大写字母表和数字