Невозможно определить, где происходит состояние гонки. В программе OPENMP в c - PullRequest
0 голосов
/ 03 марта 2019

Я пытаюсь интегрировать 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 );

   }

Я попытался добавить атомарную прагму, но это также не помогло.

Любая помощь будет оценена по достоинству:).

1 Ответ

0 голосов
/ 04 марта 2019

Проблема возникает из-за использования rand().rand() является не потокобезопасным.Причина в том, что он использует общее состояние для всех вызовов и поэтому чувствителен к гонкам. Использование stdlib's rand () из нескольких потоков

Есть поточно-безопасный генератор случайных чисел, который называется rand_r().Вместо того, чтобы хранить состояние генератора случайных изменений в скрытой глобальной переменной, состояние является параметром функции и может быть преобразовано в локальный поток.

Вы можете использовать его вот так

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

В параллельном блоке добавьте:

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

и в коде вызовите

   float x=rand_generator(3.14,&rand_state);

и это должно работать.

Кстати, у меня сложилось впечатление, что в вашем коде есть ложное совместное использование , которое должно замедлять работу.

 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

В качестве альтернативы, создайте локальную сумму в параллельном блоке и запишите ее значение в сумму [id] в конце.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...