为什么这段代码不确定?

时间:2011-08-02 15:03:29

标签: c linux multithreading pthreads

以下代码段是来自 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 都是线程的局部变量,因此不会共享。

2 个答案:

答案 0 :(得分:5)

第二次尝试。

我无法检查,但我认为在temp_p[H1] += PFORCES[ProcID][mol][dir][H1];中你添加了双打或花车。

对于浮点类型,添加顺序很重要!浮点加法不是关联

不同的线程顺序意味着不同的添加顺序。因此,预期结果会发生变化。

有关解释,请参阅http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems

答案 1 :(得分:1)

我注意到你没有显示循环变量的声明,比如moldir

可能是因为线程之间意外共享了吗?

如果是这样,所有种族条件如下:一个帖子的mol++和其他帖子的[mol % MAXLCKS]会导致问题。

更新:根据以下评论,情况似乎并非如此。