以下代码段是来自 SPLASH 2 的 water-nsq 基准的代码......
if (comp_last > NMOL1)
{
for (mol = StartMol[ProcID]; mol < NMOL; mol++)
{
pthread_mutex_lock(&gl->MolLock[mol % MAXLCKS]);
for ( dir = XDIR; dir <= ZDIR; dir++) {
temp_p = VAR[mol].F[DEST][dir];
temp_p[H1] += PFORCES[ProcID][mol][dir][H1];
temp_p[O] += PFORCES[ProcID][mol][dir][O];
temp_p[H2] += PFORCES[ProcID][mol][dir][H2];
}
pthread_mutex_unlock(&gl->MolLock[mol % MAXLCKS]);
}
comp = comp_last % NMOL;
for (mol = 0; ((mol <= comp) && (mol < StartMol[ProcID])); mol++)
{
pthread_mutex_lock(&gl->MolLock[mol % MAXLCKS]);
for ( dir = XDIR; dir <= ZDIR; dir++)
{
temp_p = VAR[mol].F[DEST][dir];
temp_p[H1] += PFORCES[ProcID][mol][dir][H1];
temp_p[O] += PFORCES[ProcID][mol][dir][O];
temp_p[H2] += PFORCES[ProcID][mol][dir][H2];
}
pthread_mutex_unlock(&gl->MolLock[mol % MAXLCKS]);
}
}
else
{
for (mol = StartMol[ProcID]; mol <= comp_last; mol++)
{
pthread_mutex_lock(&gl->MolLock[mol % MAXLCKS]);
for ( dir = XDIR; dir <= ZDIR; dir++)
{
temp_p = VAR[mol].F[DEST][dir];
temp_p[H1] += PFORCES[ProcID][mol][dir][H1];
temp_p[O] += PFORCES[ProcID][mol][dir][O];
temp_p[H2] += PFORCES[ProcID][mol][dir][H2];
}
pthread_mutex_unlock(&gl->MolLock[mol % MAXLCKS]);
}
}
pthread_barrier_wait(&(gl->start));
问题在于它最终在屏障上不具有确定性,也就是说,如果使用相同的输入执行此代码两次,它会给出不同的答案。换句话说,如果互斥锁的锁定顺序改变,则结果不同。
是的,我通过记下内存页面来验证这一点。此外,我可以向您保证,更改发生在 VAR (由 temp_p 指向)内存中。
我想知道为什么?因为很明显,所有线程都将自己的值(PFORCES [ ProcID ] ...)添加到 temp_p 的总和中,最后,这就是障碍,结果应该是相同的,无论线程获取锁的顺序如何。
[已编辑]
另请注意,变量 comp , dir 和 mol 都是线程的局部变量,因此不会共享。
答案 0 :(得分:5)
第二次尝试。
我无法检查,但我认为在temp_p[H1] += PFORCES[ProcID][mol][dir][H1];
中你添加了双打或花车。
对于浮点类型,添加顺序很重要!浮点加法不是关联!
不同的线程顺序意味着不同的添加顺序。因此,预期结果会发生变化。
有关解释,请参阅http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems。
答案 1 :(得分:1)
我注意到你没有显示循环变量的声明,比如mol
和dir
。
可能是因为线程之间意外共享了吗?
如果是这样,所有种族条件如下:一个帖子的mol++
和其他帖子的[mol % MAXLCKS]
会导致问题。
更新:根据以下评论,情况似乎并非如此。