2016-08-04 12 views
2

Ich habe ein kleines Stück Code, den ich parallelisieren möchte, wie ich upscale. Ich habe cilk_for von Cilk Plus verwendet, um das Multithreading auszuführen. Das Problem ist, dass ich je nach Anzahl der Arbeiter ein anderes Ergebnis bekomme.Cilk Plus Code Ergebnis hängt von der Anzahl der Arbeiter

Ich habe gelesen, dass dies auf eine Race-Bedingung zurückzuführen sein könnte, aber ich bin mir nicht sicher, was speziell über den Code verursacht oder wie es zu verbessern. Außerdem stelle ich fest, dass long und __float128 Overkill für dieses Problem sind, aber möglicherweise in der Upscaling notwendig sind.

Code:

#include <assert.h> 
#include "cilk/cilk.h" 
#include <cstring> 
#include <iostream> 
#include <math.h> 
#include <stdio.h> 
#include <string> 
#include <vector> 

using namespace std; 

__float128 direct(const vector<double>& Rpct, const vector<unsigned>& values,  double Rbase, double toWin) { 
    unsigned count = Rpct.size(); 
    __float128 sumProb = 0.0; 
    __float128 rProb = 0.0; 
    long nCombo = static_cast<long>(pow(2, count)); 

// for (long j = 0; j < nCombo; ++j) { //over every combination 
    cilk_for (long j = 0; j < nCombo; ++j) { //over every combination 
     vector<unsigned> binary; 

     __float128 prob = 1.0; 
     unsigned point = Rbase; 

     for (unsigned i = 0; i < count; ++i) { //over all the individual events 
      long exp = static_cast<long>(pow(2, count-i-1)); 
      bool odd = (j/exp) % 2; 
      if (odd) { 
       binary.push_back(1); 
       point += values[i]; 
       prob *= static_cast<__float128>(Rpct[i]); 
      } else { 
       binary.push_back(0); 
       prob *= static_cast<__float128>(1.0 - Rpct[i]); 
      }    
     } 

     sumProb += prob; 
     if (point >= toWin)   rProb += prob; 
     assert(sumProb >= rProb); 
    } 

    //print sumProb 
    cout << " sumProb = " << (double)sumProb << endl; 
    assert(fabs(1.0 - sumProb) < 0.01); 

    return rProb; 
} 

int main(int argc, char *argv[]) { 
    vector<double> Rpct; 
    vector<unsigned> value; 

    value.assign(20,1); 
    Rpct.assign(20,0.25); 

    unsigned Rbase = 22; 
    unsigned win = 30; 

    __float128 rProb = direct(Rpct, value, Rbase, win); 

    cout << (double)rProb << endl; 

    return 0; 
} 

Beispielausgabe für export CILK_NWORKERS=1 && ./code.exe:

sumProb = 1

0,101812

Beispielausgabe für export CILK_NWORKERS=4 && ./code.exe:

sumProb = 0,948159

Assertion fehlgeschlagen: (Fabs (1,0 - sumProb) < 0,01), Funktion direkt, Datei code.c, Zeile 61.

Abort trap: 6

Antwort

1

Es ist wegen einer Wettlaufsituation. cilk_for ist die Implementierung der Parallele für den Algorithmus. Wenn Sie parallel für Sie verwenden möchten, müssen Sie unabhängige Iteration verwenden (unabhängige Daten). Es ist sehr wichtig. Sie müssen Cilk Reducer für Ihren Fall verwenden: https://www.cilkplus.org/tutorial-cilk-plus-reducers

+1

Definition von 'sumProb' und' rProb' als 'cilk :: reducer >' hat den Trick gemacht. Ich verstehe, dass der gleichzeitige Zugriff, das Bearbeiten und Speichern dieser Variablen zu fehlerhaften Ergebnissen führen kann. Ich würde mir vorstellen, dass, wenn ich sie stattdessen in einem Vektor speichern würde und dann summieren würde, würde der Vektor außerhalb der For-Schleife auch funktionieren. – Stershic

1

Um zu verdeutlichen, gibt es mindestens eine Rasse auf SumProb. Jeder der parallelen Worker liest/ändert/schreibt an diesem Ort. Wie oben erwähnt, ist die Lösung solcher Probleme das, was Reducer sind.

Es ist durchaus möglich, dass mehr als eine Rasse in Ihrem Programm ist. Der einzige Weg, um sicher zu sein, ist es unter einem Race-Detektor laufen, da das Finden von Rennen ist eines der Dinge, die Computer sind besser als Menschen. Eine kostenlose Möglichkeit ist der Cilkscreen Race Detector, der unter der cilkplus.org Website verfügbar ist. Leider unterstützt es gcc/g ++ nicht.