2016-08-04 84 views
2

我有一小段代码,我想高级并行化。我一直在使用Cilk Plus的cilk_for来运行多线程。麻烦的是,根据工人的数量,我得到了不同的结果。Cilk Plus代码结果取决于工作人员的数量

我读过,这可能是由于竞争条件,但我不确定代码的具体内容导致或如何改善它。另外,我意识到long__float128对于这个问题是矫枉过正的,但在升级中可能是必需的。

代码:

#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; 
} 

示例输出为export CILK_NWORKERS=1 && ./code.exe

sumProb = 1

0.101812

示例输出为export CILK_NWORKERS=4 && ./code.exe

sumProb = 0.948159

断言失败:(FABS(1.0 - sumProb)< 0.01),功能直接,文件code.c,线61

中止陷阱:6

回答

1

这是因为比赛条件。 cilk_for是算法的并行实现。如果你想使用并行,你必须使用独立迭代(独立数据)。这是非常重要的。你必须为你的情况使用cilk reducer:https://www.cilkplus.org/tutorial-cilk-plus-reducers

+1

将'sumProb'和'rProb'定义为'cilk :: reducer >'做了诡计。我明白这是同时访问,编辑和保存这些可能导致错误结果的变量。我会想象如果我将它们保存到一个向量中,然后在for循环之外总结该向量也会起作用。 – Stershic

1

为了澄清,sumProb上至少有一场比赛。每个平行工作人员将在该位置进行读取/修改/写入。正如上面提到的斯克林,解决这样的问题是减速器的目的。

完全有可能您的程序中有多个种族。唯一可以肯定的方法是在赛跑探测器下运行它,因为寻找比赛是计算机比人类更擅长的事情之一。免费的可能性是Cilkscreen赛跑探测器,可从cilkplus.org网站获得。不幸的是,它不支持gcc/g ++。