需要帮助使ran2和主程序并行化,导致分段错误openmp

时间:2019-06-25 16:03:45

标签: c openmp

我试图并行化循环,但是增加线程数使我陷入“分段错误(内核已转储)”

我已经在main.c中并行化了循环,该循环内部引用了ran2.c文件功能,这在某处导致我出现分段错误,我需要帮助来并行化程序。

main.c:

#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv) {
    int niter, i, j;
    long seed;
    double count;
    double x,y,z,pi;
    extern float ran2();
    niter=10000;
    count=0;

    #pragma omp parallel firstprivate(x, y, z, i) shared(count) num_threads(4)
    for(i=1; i<=niter; i++) {
        seed=i;
        x=ran2(&seed);
        y=ran2(&seed);
        z=x*x+y*y;
        if(z<1) {
            count+=1;
        }
    }
    pi=count*4.0/niter;
    printf("The value of pi is %8.14f\n",pi);
    return 0;
}

ran2.c


#define IM2 2147483399
#define IM1 2147483563
#define AM (1.0/IM1)
#define IMM1 (IM1-1)
#define IA1 40014
#define IA2 40692
#define IQ1 53668
#define IQ2 52774
#define IR1 12211
#define IR2 3791
#define NTAB 32
#define NDIV (1+IMM1/NTAB)
#define EPS 1.2e-7
#define RNMX (1.0-EPS)

float ran2(long *idum) {
    int j;
    long k;
    static long idum2=123456789;
    static long iy=0;
    static long iv[NTAB];
    float temp;
    if (*idum <= 0) {
        if (-(*idum) < 1)
            *idum=1;
        else *idum = -(*idum);
        idum2=(*idum);
        for (j=NTAB+7; j>=0; j--) {
            k=(*idum)/IQ1;
            *idum=IA1*(*idum-k*IQ1)-k*IR1;
            if (*idum < 0)
                *idum += IM1;
            if (j < NTAB)
                iv[j] = *idum;
        }
        iy=iv[0];
    }
    k=(*idum)/IQ1;
    *idum=IA1*(*idum-k*IQ1)-k*IR1;
    if (*idum < 0)
        *idum += IM1;
    k=idum2/IQ2;
    idum2=IA2*(idum2-k*IQ2)-k*IR2;
    if (idum2 < 0)
        idum2 += IM2;
    j=iy/NDIV;
    iy=iv[j]-idum2;
    iv[j] = *idum;
    if (iy < 1)
        iy += IMM1;
    if ((temp=AM*iy) > RNMX)
        return RNMX;
    else
        return temp;
}


我需要并行化程序。

1 个答案:

答案 0 :(得分:0)

您的代码有几个问题。

首先,您要使用xyzfirstprivate的未初始化值传递给每个OpenMP线程,编译器会对此进行警告。通过将内部声明移至for循环并删除firstprivate,可以轻松解决此问题。出于相同的原因,i应该是private

seed应该在每次迭代期间保持不变,但是由于它是一个共享变量,因此线程正在竞争将其值写入其中。通过将seed的声明移入循环也可以解决此问题。

第三个问题是,在写入count时线程也在加速。由于要对不同线程中的值求和,因此应使用reduction(+:count)指令。

第四,ran2函数不是线程安全的。它具有idum2iyiv形式的静态,线程再次在其中竞争。解决此问题的最佳方法是通过将全局状态移动到作为参数传递的struct ran_state(参见下文)中来摆脱全局状态。然后,将引用idum2的每个位置替换为state->idum2,将iy替换为iy,将state->iv替换为state->iv。最后,在for循环之前创建并初始化此状态,并将其标记为firstprivate,以便每个线程都获得自己的初始化状态。

然后如下所示(为了方便起见,在一个文件中):

#include <stdlib.h>
#include <stdio.h>

// Insert the #defines for ran2 here ...

struct ran_state {
    long idum2;
    long iy;
    long iv[NTAB];
};

// Insert ran2 here, replacing iv with state->iv, and so on ...

int main(int argc, char **argv){
    int niter, i;
    double count;
    double pi;
    niter=10000;
    count=0;
    struct ran_state state = { 123456789, 0, {0} };

#pragma omp parallel for reduction(+:count) firstprivate(state) private(i) num_threads(4)
    for(i=1;i<=niter;i++){
        double x, y, z;
        long seed;
        seed=i;
        x=ran2(&seed, &state);
        y=ran2(&seed, &state);
        z=x*x+y*y;
        if(z<1){
            count+=1;
        }
    }
    pi=count*4.0/niter;
    printf("The value of pi is %8.14f\n",pi);
    return 0;
}