英特尔TBB parallel_reduce返回错误结果

时间:2015-04-23 04:33:33

标签: c++ parallel-processing intel tbb

我正在尝试使用英特尔TBB parallel_reduce来计算对Connect 4游戏中用户移动的最佳响应。我写了一个简单的函数,当传递一个列号时,返回一个与播放该移动的效用相对应的启发式分数。我的意图是并行调用此函数,然后返回返回结果的减少。减少将是具有最高启发式分数的移动。

然而,我发现结果不一致。我希望第0列的移动可以从并行缩减中返回(因为我已经编写了启发式分数函数,因此它返回7 - 列号作为分数)。

我附上了C ++代码。以下是它生成的示例输出:

  

返回0

     

返回移动1

     

返回举动2

     

返回举动6

     

返回移动4

     

返回举动5

     

比较动作5Return move 3& 6

     

比较动作3& 4

     

比较动作3& 5

     

比较动作2& 3

     

最佳举措是2

我已多次查看代码并且无法理解为什么它并不总是返回0作为最佳动作。它有时会返回零,但并非总是如此。如上所示,移动0被评估,但是简化lambda函数永远不会将其作为输入。任何帮助将不胜感激。我有一种模糊的怀疑,即我所使用的0的身份,可能不对。但是,我不确定它应该是什么。

#include <tbb\blocked_range.h>
#include <tbb\parallel_reduce.h>

#include <iostream>
#include <vector>

int getMoveHueristicScore(int columnCounter) {

    int returnValue = 7 - columnCounter;
    return returnValue;
}

int bestHeuristicScore(int numberOfColumns) {

    std::vector<int> moveScores(numberOfColumns, -1 * INT_MAX);

    return tbb::parallel_reduce(
        tbb::blocked_range<int>(0, numberOfColumns),
        0,
        [=, &moveScores](const tbb::blocked_range<int>& range, int bestMove)->int {
        int bestScore = -1 * INT_MAX;
        for (int columnCounter = range.begin(); columnCounter != range.end(); ++columnCounter) {
            moveScores.at(columnCounter) = getMoveHueristicScore(columnCounter);
            if (moveScores.at(columnCounter) > bestScore) {
                bestScore = moveScores.at(columnCounter);
                bestMove = columnCounter;
            }
        }
        std::cout << "Return move " << bestMove << std::endl;
        return bestMove;
    },
        [=, &moveScores](int bestMove1, int bestMove2)->int {
        std::cout << "Compare moves " << bestMove1 << " & " << bestMove2 << std::endl;
        if (moveScores.at(bestMove1) > moveScores.at(bestMove2)) {
            return bestMove1;
        }
        else {
            return bestMove2;
        }
    }
    );
}

int main() {

    int bestMove = bestHeuristicScore(7);
    std::cout << "Best move is " << bestMove << std::endl;
    return 0;
}

3 个答案:

答案 0 :(得分:3)

在这种情况下,tbb::parallel_reduce没有问题。问题是您的代码忽略了init函数的func参数。

TBB有如何执行减少的不同选项。它可以选择为不同线程中的不同子范围调用func,然后使用reduction函数组合结果;它可以在同一个线程中多次调用func,每次传递前一次调用的结果;或者它可以结合使用这两种策略。

查看func的实施情况:

[=, &moveScores](const tbb::blocked_range<int>& range, int bestMove)->int {
    int bestScore = -1 * INT_MAX;
    for (int columnCounter = range.begin(); columnCounter != range.end(); ++columnCounter) {
        moveScores.at(columnCounter) = getMoveHueristicScore(columnCounter);
        if (moveScores.at(columnCounter) > bestScore) {
            bestScore = moveScores.at(columnCounter);
            bestMove = columnCounter;
        }
    }
    std::cout << "Return move " << bestMove << std::endl;
    return bestMove;
}

永远不会使用init参数bestMove;相反,值bestScore被初始化为某个虚拟值。 TBB可以多次调用func,每次传入前一次调用的计算bestMove,但这会被忽略,因此最终结果将是来自任何子范围的bestMove。传递给了最后一个电话。

修复方法是使用bestMove初始化最佳分数,如下所示:

int bestScore = moveScores.at(bestMove);

然后,TBB将从func的一次调用中获得最佳分数,确保最终结果确实是全球最佳分数。

答案 1 :(得分:0)

您声称缩减的左侧身份是0,显然不是这种情况。您必须提供此类身份,并在减速器中处理。尝试-1并明确处理它。

并且-INT_MAX关闭了1。

在遇到错误时明确捕获(删除=)。了解捕获的内容有时会有很大帮助。

我很惊讶您的示例输出在减少时没有提及1,但我对0的缺失并不感到惊讶。

答案 2 :(得分:0)

您正在从多个线程访问std::vector,这是不安全的。这可能是您问题的根源。将您的moveScores容器更改为tbb::concurrent_vector<int>