Почему этот код не является детерминированным? - PullRequest
2 голосов
/ 02 августа 2011

Следующий фрагмент кода из 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  <= 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 , и в конце, то есть на барьере, результаты должныбыть одинаковыми, независимо от того, в каком порядке потоки приобрели блокировки.

[EDITED]

Также обратите внимание, что переменные comp , dir и моль являются локальными переменнымипоток и, следовательно, не разделяется.

Ответы [ 2 ]

5 голосов
/ 02 августа 2011

Вторая попытка.

Я не могу это проверить, но я предполагаю, что в temp_p[H1] += PFORCES[ProcID][mol][dir][H1]; вы добавляете двойные или плавающие числа.

Для типов с плавающей запятой порядок сложения имеет значение! Добавление с плавающей запятой не ассоциативно !

Другой порядок потоков означает другой порядок добавления. Поэтому следует ожидать изменений в результате.

См. http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems для некоторых объяснений.

1 голос
/ 02 августа 2011

Я заметил, что вы не показываете объявление переменных цикла, таких как mol и dir.

Может ли случиться так, что они будут случайно разделены между потоками?

ЕслиИтак, все виды состязаний между, например, mol++ одного потока и [mol % MAXLCKS] другого потока вызовут проблемы.

ОБНОВЛЕНИЕ : Согласно комментариям ниже, это не похоже надело.

...