我不知道为什么,但是此循环的并行化工作不正常:
#pragma omp parallel for private(d)
for ( i = 0 ; i < nt1 ; i++ ) {
d = distancia(tabla1[i],tabla2[j]);
if ( d < dm ) {
#pragma omp critical
if ( d < dm ) {
dm = d;
im = i;
}
}
}
ps[j] = im;
d
变量是私有变量,dm
和im
在关键区域内,但是当我执行此代码时(完整代码较大,这只是其中的一小部分)它)输出从顺序版本更改。
谢谢!
答案 0 :(得分:0)
第一个if ( d < dm )
在 critical 部分之外,可能是导致争用情况的原因。应该将其删除,因为 critical 部分中已经存在一个。如果您的目的是避免在关键部分过分频繁,那么这不是这样做的方法(请参阅下文)。您可能也必须手动刷新dm(有关#pragma omp flush
的一些说明,请参见here)。
distancia
函数也可能不是线程安全的(即,依赖于某些不能由多个线程同时编辑的全局变量)。
此外,如果某些距离值相等,则结果不同是正常的。由于没有专门处理这种情况的规则(即采用最小的im
),因此将保留遇到的第一个最小值的索引:串行和并行版本中的最小值可能与迭代的顺序不同。
除非distancia
函数的计算需要占用大量CPU,否则由于多种原因,您的代码运行速度可能会比串行代码慢。值得注意的是,关键部分的同步开销和变量为dm
的缓存共享问题。
最好使用归约方法,其中每个线程计算要执行的任何迭代的最小值,而全局最小值被视为所有线程的最小局部最小值。
float dm=INFINITY;
int im=-1;
#pragma omp parallel shared(dm,im)
{
// Declare private variables
float d,dmin_thread,imin_thread;
dmin_thread=INFINITY;
imin_thread=-1;
// loop through i
#pragma omp for
for ( i = 0 ; i < nt1 ; i++ ) {
d = some_function(i);
// the following lines operate on thread-private variables
if ( d < dmin_thread) {
dmin_thread= d;
imin_thread= i;
}
}// end for
// Reduction part after the loop has been completed
// The critical section is entered only once by each thread
#pragma omp critical
{
if ( dmin_thread < dm) {
dm = dmin_thread;
im = imin_thread;
}
}//end critical
}//end parallel
if(im==-1)
throw_some_error();
else
do_something_with(im);
答案 1 :(得分:0)
我认为问题在于,即使它是一个关键区域,在顺序版本中,我们也始终会获得最低的i
值并添加以下条件:(dm == d && i < im)
在条件中我们确保代码仍然以相同的方式工作。我不确定这是否是最好的解决方案,但它非常简单并且对我有用。
这是带有更改的完整代码:
for ( j = 0 ; j < nt2 ; j++ ) {
dm = MAX_LON + 1;
#pragma omp parallel for private(d)
for ( i = 0 ; i < nt1 ; i++ ) {
d = distancia(tabla1[i],tabla2[j]);
if ( d < dm || (dm == d && i < im)) {
#pragma omp critical
{
if ( d < dm || (dm == d && i < im)) {
dm = d;
im = i;
}
}
}
}
ps[j] = im;
}