c - 为什么这段代码不是确定性的?

标签 c linux multithreading pthreads

以下代码片段是来自 SPLASH 2water-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 的总和中,最后,即在屏障处,无论线程获取锁的顺序如何,结果都应该相同。

[编辑]

另外,请注意变量 compdirmol 都是线程的局部变量,因此不共享。

最佳答案

第二次尝试。

我无法检查它,但我假设在 temp_p[H1] += PFORCES[ProcID][mol][dir][H1]; 中您正在添加 double 或 float 。

对于浮点类型,加法的顺序很重要!浮点加法不结合!

不同的线程顺序意味着不同的添加顺序。因此,结果的变化是可以预料的。

参见http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems一些解释。

关于c - 为什么这段代码不是确定性的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6914180/

相关文章:

c++ - 如何获得结构或类的尾随填充的大小?

c - 我如何制作 strncpy 函数?

c - OpenCV 2.3.0+ : cvCaptureFromCAM returns null

在 Ubuntu 上使用 SSL 的 MySQL ODBC 连接

c++ - 使用互斥量的正确方法

c# - 在另一个线程的主线程中显示表单

c - 使用openssl计算base64文件摘要

c - 需要帮助理解 while 循环

linux - perl 脚本执行时间非常慢

c++ - 跨线程的内存分配和释放