C 为什么这个代码不是确定性的?
下面的代码片段是来自water nsq的代码,来自SPLASH 2C 为什么这个代码不是确定性的?,c,linux,multithreading,pthreads,C,Linux,Multithreading,Pthreads,下面的代码片段是来自water nsq的代码,来自SPLASH 2 if (comp_last > NMOL1) { for (mol = StartMol[ProcID]; mol < NMOL; mol++) { pthread_mutex_lock(&gl->MolLock[mol % MAXLCKS]); for ( dir = XDIR; dir <=
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));
if(comp\u last>NMOL1)
{
对于(mol=StartMol[ProcID];molMolLock[mol%MAXLCKS]);
对于(dir=XDIR;dir-MolLock[mol%MAXLCKS]);
}
comp=comp_最后%NMOL;
对于(mol=0;((mol MolLock[mol%MAXLCKS]);
对于(dir=XDIR;dir-MolLock[mol%MAXLCKS]);
}
}
其他的
{
对于(mol=StartMol[ProcID];mol-MolLock[mol%MAXLCKS]);
对于(dir=XDIR;dir-MolLock[mol%MAXLCKS]);
}
}
pthread_barrier_wait(&(gl->start));
问题在于,它最终在屏障处是不确定的,也就是说,如果您使用相同的输入执行此代码两次,它会给出不同的答案。换句话说,如果更改互斥锁的锁顺序,结果是不同的
是的,我已经通过记录内存页验证了这一点。我还可以向您保证,变化发生在VAR(由temp指向)内存中
我想知道为什么?因为显然,所有线程都将自己的值(PFORCES[ProcID])加在temp的和上,最后,也就是在屏障处,结果应该是相同的,无论线程获取锁的顺序如何
[已编辑]
另外,请注意变量comp、dir和mol都是线程的局部变量,因此不共享。我注意到您没有显示循环变量的声明,如
mol
和dir
可能是线程之间意外共享了数据吗
如果是这样,例如一个线程的mol++
和另一个线程的[mol%MAXLCKS]
之间的所有类型的争用条件都会导致问题
更新:根据下面的评论,情况似乎并非如此。第二次尝试
我无法检查它,但我假设在temp_p[H1]+=PFORCES[ProcID][mol][dir][H1];
中添加了双精度或浮点
对于浮点类型,加法的顺序很重要!浮点加法不是关联的
不同的线程顺序意味着不同的添加顺序。因此,预期结果会发生变化
请参阅以获取一些解释。发布完整的工作代码。这是在哪个处理器系列上运行的?并非所有处理器都具有相同的缓存一致性保证。您可能需要查看内存围栏。Nawaz,您可以从网站上获得这一代码。基准名称是water-nsq.spraff,它在x86上运行。我在单核和单核上都运行它d双核,但在这两种情况下,我得到了相同的行为。内存隔离应该是多核的问题,不是吗?在我看来。这段代码非常需要重构。我不知道这两种情况之间有什么不同。当你有那么多接近重复的代码时,会调用另一个函数。不,我可以向你确认mol和dir是lo线程的cal变量,不是共享的。@metallicprate好吧,没有显示完整的代码,我只能猜测。很有趣!是的temp是双精度的。有什么方法可以解决这个问题吗?很好的答案!我想这正是它不确定的原因。但非常令人惊讶的事实:)!解决什么?所使用的算法本质上是不确定的。如果这是一个问题,则算法的选择是不正确的。例如,您可以切换到定点数学,以确保加法顺序无关紧要。