在OpenMP

时间:2015-12-03 03:19:57

标签: c parallel-processing openmp

我有一个代码,我想使用OpenMP进行并行化。该程序演示了一个执行多项式插值的函数。首先,我想到在代码中的许多函数之一内并行化一个for循环。这个的串行版本是这样的:

void polint (double xa[], double ya[], int n, double x, double *y, double *dy) {
    int i, m, ns=1;
    double den,dif,dift,ho,hp,w;
    double *c, *d;
    dif = fabs(x-xa[1]); c = vector(1,n);
    d = vector(1,n); for (i=1; i<= n; i++) { 
        dift = fabs (x - xa[i]); 
        if (dift<dif) {
            ns = i;
            dif = dift;
        }
        c[i] = ya[i];
        d[i] = ya[i]; 
    }
    *y = ya[ns--];
    for (m = 1; m < n; m++) { 
        for (i = 1; i<= n-m; i++) {
            ho = xa[i] - x;
            hp = xa[i+m] - x;
            w = c[i+1] - d[i]; den = ho - hp;
            den = w / den; d[i] = hp * den; c[i] = ho * den;
        }
    *y += (*dy=(2*ns < (n-m) ? c[ns+1] : d[ns--])); 
    }
    free_vector (d, 1, n); free_vector (c, 1, n); 
}

现在,使用OpenMP,我构建了这段代码:

void polint (double xa[], double ya[], int n, double x, double *y, double *dy) {
    int i, m, ns=1;
    double den,dif,dift,ho,hp,w;
    double *c, *d;
    int nth;
    dif = fabs(x-xa[1]); c = vector(1,n);
    d = vector(1,n); for (i=1; i<= n; i++) { 
        dift = fabs (x - xa[i]); 
        if (dift<dif) {
            ns = i;
            dif = dift;
        }
        c[i] = ya[i];
        d[i] = ya[i]; 
    }
    #pragma omp parallel
    {
    *y = ya[ns--];    
        nth = omp_get_num_threads();
        for (m = 1; m < n; m++) {
            #pragma omp for 
            for (i = 1; i<= n-m; i++) {
                #pragma omp critical 
                {
                    ho = xa[i] - x;
                    hp = xa[i+m] - x;
                    w = c[i+1] - d[i]; den = ho - hp;
                    den = w / den; d[i] = hp * den; c[i] = ho * den;
                }
            }
            #pragma omp critical
            *y += (*dy=(2*ns < (n-m) ? c[ns+1] : d[ns--])); 
        }
        free_vector (d, 1, n); free_vector (c, 1, n);
    } 
}

程序编译正确,但问题来自于我运行它。我收到以下错误消息:

Error message displayed when running the program

我该如何解决这个问题?我首先想到的是数组被超越,所以我添加了关键区域,以便许多进程不会同时访问数组。但是,这并没有解决问题。 提前谢谢!

1 个答案:

答案 0 :(得分:3)

除了显而易见的cd指针释放产生你遇到的崩溃之外,你的代码中还有很多问题。为了更好地指出它们,我用更合理的变量声明和正确的缩进重写了顺序函数。以下是它给我的信息:

void polint( double xa[], double ya[], int n, double x, double *y, double *dy ) {
    double *c = vector( 1, n );
    double *d = vector( 1, n );

    double dif = fabs( x - xa[1] );
    int ns = 1;
    for ( int i = 1; i <= n; i++ ) { 
        double dift = fabs( x - xa[i] ); 
        if ( dift < dif ) {
            ns = i;
            dif = dift;
        }
        c[i] = ya[i];
        d[i] = ya[i]; 
    }

    *y = ya[ns--];
    for ( int m = 1; m < n; m++ ) { 
        for ( int i = 1; i <= n - m; i++ ) {
            double ho = xa[i] - x;
            double hp = xa[i + m] - x;
            double den = ( c[i + 1] - d[i] ) / ( ho - hp );
            d[i] = hp * den;
            c[i] = ho * den;
        }
        *dy = 2 * ns < ( n - m ) ? c[ns + 1] : d[ns--];
        *y += *dy; 
    }

    free_vector( d, 1, n );
    free_vector( c, 1, n ); 
}

现在,阅读代码变得更简单了(虽然它仍然非常模糊)并且一些问题变得明显:

  • 您是否声明要将数组从1索引到n而不是从0n-1?如果是这样,这是不寻常的(并且容易出错)。如果没有,你的循环中可能会出现一些问题(尤其是第一个i循环)。
  • dy的值在m循环的每次迭代中重写。知道这是一个输出参数,这意味着它的最终值只是与m的最后一个值相对应的值。这不是一个问题,但它看起来很可疑......你确定它是正确的吗?
  • 现在,关于可能的并行化,我们可以从den的定义和c c[i]的后续更新看出c[i+1]取决于private。从并行化的角度来看,这是一个大问题。这意味着现在编写代码的方式,它无法并行化。这并没有完全关闭并行化的大门,但这只是意味着还有更多的工作要做,而不仅仅是使用一些OpenMP指令来实现它。

现在,除了这些问题之外,如果我们看一下您的并行版本,还有很多其他问题:

  • 已经提到过,并行区域内的向量释放:它绝对应该移到外面。
  • 存在极大问题,您没有声明m应该包含的数据:至少hohpwden和{{ 1}}应该声明private。此外,我强烈怀疑*y应该声明reduction(+)*dy应该声明lastprivate(尽管正确执行此操作的确切方法需要更精细的调整)。< / LI>
  • 为了弥补private声明的缺失,您将并行循环的整个主体包含在critical区域中,基本上将其重新序列化。不幸的是,它既是超感染又是错误的,因为正如我们所看到的,迭代的顺序很重要,而这并不能保留它......

总而言之,我强烈建议你做一些事情:

  1. 这非常重要,对代码进行去混淆和清理:正确缩进,为变量赋予有意义的名称,每行保留一个语句,尽可能在代码中声明变量并立即初始化它们。这里和那里有一两个明智的评论可以派上用场。
  2. 打破i的{​​{1}}依赖关系。这可以通过保留它的两个副本(一个对应于c循环的上一次迭代中的值,一个对应于其当前值)来轻松完成。
  3. 添加OpenMP指令时,请注意将变量正确声明为m等。好消息是,如果你按照我的建议做了并尽可能地延迟了他们的声明,那么你很可能很少需要照顾,因为大多数声明都在private区域内,做出相应的变量应该自动parallel
  4. 有了这个,您应该能够获得正确且(希望)有效的代码并行版本。