Cilk Plus 代码结果取决于工人数量

Cilk Plus code result depends on number of workers

我有一小段代码想在升级时并行化。我一直在使用 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

Assertion failed: (fabs(1.0 - sumProb) < 0.01), function direct, file code.c, line 61.

Abort trap: 6

这是因为竞争条件。 cilk_for是算法的并行实现。如果你想使用parallel for你必须使用independent iteration(独立数据)。这是非常重要的。您必须为您的案例使用 cilk reducer:https://www.cilkplus.org/tutorial-cilk-plus-reducers

澄清一下,sumProb 上至少有一场比赛。每个并行工作人员将在该位置执行 read/modify/write。上面sribin说的,解决这样的问题就是reducer的作用

您的计划中完全有可能有不止一场比赛。唯一可以确定的方法是 运行 它在种族检测器下,因为发现种族是计算机比人类 擅长的事情之一。一个免费的可能性是 Cilkscreen 竞争检测器,可从 cilkplus.org 网站获得。不幸的是它不支持 gcc/g++。