[英]Using critical region with 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);
}
}
程序编译正确,但问题来自于我运行它。 我收到以下错误消息:
我怎么解决这个问题? 我首先想到的是数组被超越,所以我添加了关键区域,以便许多进程不会同时访问数组。 但是,这并没有解决问题。 提前致谢!
除了产生你遇到的崩溃的c
和d
指针的明显释放之外,你的代码中还存在很多问题。 为了更好地指出它们,我用更合理的变量声明和正确的缩进重写了顺序函数。 这是它给我的东西:
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
而不是0
到n-1
索引? 如果是这样,这是不寻常的(并且容易出错)。 如果没有,你的循环可能会有一些问题(第一个i
循环显着)。 m
循环的每次迭代中都重写了dy
的值。 知道这是一个输出参数,这意味着它的最终值只是与m
的最后一个值相对应的值。 这不是一个问题,但它看起来很可疑......你确定它是正确的吗? den
的定义和c
的后续更新看出c[i]
取决于c[i+1]
。 从并行化的角度来看,这是一个大问题。 这意味着现在编写代码的方式,它无法并行化。 这并没有完全关闭并行化的大门,但这只是意味着还有更多的工作要做,而不仅仅是使用一些OpenMP指令来获取它。 现在,除了这些问题之外,如果我们看一下您的并行化版本,还有很多其他问题:
private
的数据:至少, m
, ho
, hp
, w
和den
应该声明为private
。 此外,我强烈怀疑*y
应该声明reduction(+)
并且*dy
应该声明为lastprivate
(尽管正确地执行该操作需要更精细的调整)。 private
声明的缺失,您将并行循环的整个主体包含在critical
区域中,基本上将其重新序列化。 不幸的是,它既是超感染又是错误的,因为正如我们所看到的,迭代的顺序很重要,而这并不能保留它...... 总而言之,我强烈建议你做一些事情:
c
的i
依赖性。 这可以通过保留它的两个副本(一个对应于m
循环的前一次迭代中的值,一个对应于其当前值)来完成。 private
等。 好消息是,如果你按照我的建议做了并尽可能地推迟了他们的声明,那么你很可能很少需要照顾,因为大多数声明都在parallel
区域内,因此相应的变量会自动private
应该。 有了这个,您应该能够获得正确且(希望)有效的代码并行版本。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.