通过参考TBB任务传递函数时无法返回值

时间:2017-07-30 20:09:23

标签: c++ c++11 parallel-processing tbb

我正在尝试使用英特尔TBB,并试图弄清楚当我通过引用传递函数时,为什么我不能通过引用TBB任务来填充传入的向量。

以下是代码:

// tbbTesting.cpp : Defines the entry point for the console application.

#include "stdafx.h"

#include "tbb/task.h"

#include <functional>
#include <iostream>
#include <random>

#define NUM_POINTS 10


void myFunc(std::vector<double>& numbers)
{
   std::mt19937_64 gen;
   std::uniform_real_distribution<double> dis(0.0, 1000.0);

   for (size_t i = 0; i < NUM_POINTS; i++)
   {
      auto val = dis(gen);
      std::cout << val << std::endl; //proper values generated
      numbers.push_back(val);  //why is this failing?
   }

   std::cout << std::endl;

   for (auto i : numbers)
   {
      std::cout << numbers[i] << std::endl; //garbage values
   }
}


class TASK_generateRandomNumbers : public tbb::task
{
public:
   TASK_generateRandomNumbers(std::function<void(std::vector<double>&)>& fnc, 
std::vector<double>& nums) : _fnc(fnc), _numbers(nums) {}
   ~TASK_generateRandomNumbers() {};

   tbb::task* execute()
   {
      _fnc(_numbers);
      return nullptr;
   }

private:
   std::function<void(std::vector<double>&)>& _fnc;
   std::vector<double>& _numbers;
};


class Manager
{
public:
   Manager() { _numbers.reserve(NUM_POINTS); }
   ~Manager() {}

   void GenerateNumbers()
   {
        _fnc = std::bind(&myFunc, _numbers);
        TASK_generateRandomNumbers* t = new(tbb::task::allocate_root()) 
        TASK_generateRandomNumbers(_fnc, _numbers);
        tbb::task::spawn_root_and_wait(*t);
   }

   auto GetNumbers() const { return _numbers; }

private:
   std::function<void(std::vector<double>&)> _fnc;
   std::vector<double> _numbers;
};



int main()
{
   Manager mgr;
   mgr.GenerateNumbers();
   auto numbers = mgr.GetNumbers(); //returns empty
}

execute方法执行操作时,我可以通过引用传递向量时获取值。

execute方法必须调用一个函数时,我会将垃圾数据打印到控制台(push_back失败?),并在返回时得到一个空容器。

任何人都能看到我失踪的东西吗?感谢。

1 个答案:

答案 0 :(得分:1)

我发现了一些与tbb无关的错误。

1)你的myFunc使用范围不正确。它不会返回索引,而是依次直接在向量中返回每个值。你的代码将每个double转换为int并将其作为数组的索引使用,这就是为什么你是gettign garbage。

2)当您使用std :: bind创建一个仿函数时,参数将按值复制。如果你想传入一个引用,那么你需要使用std :: ref来包装参数。

如果您使用的是c ++ 11,那么您可能需要考虑使用lambda而不是bind。

我用不同的方式使用myFunc编写了一个小程序:使用和不使用std :: ref以及lambda示例。您应该看到它生成相同的数字3次,但是当它尝试打印出v1时它不会包含任何内容,因为生成的值被放在副本中。

#include <vector>
#include <random>
#include <iostream>
#include <functional>

constexpr size_t NUM_POINTS = 10;

void myFunc(std::vector<double>& numbers)
{
    std::mt19937_64 gen;
    std::uniform_real_distribution<double> dis(0.0, 1000.0);

    for (size_t i = 0; i < NUM_POINTS; i++)
    {
         auto val = dis(gen);
         std::cout << val << std::endl; //proper values generated
         numbers.push_back(val);  //why is this failing? it's not
    }

    std::cout << std::endl;
}

void printNumbers(std::vector<double>const& numbers)
{
    for (auto number : numbers)
    {
        std::cout << number << std::endl; 
    }
    std::cout << std::endl;
}

int main()
{
    std::cout << "generating v1" << std::endl;
    std::vector<double> v1;
    auto f1 = std::bind(&myFunc, v1);
    f1();
    printNumbers(v1);

    std::cout << "generating v2" << std::endl;
    std::vector<double> v2;
    auto f2= std::bind(&myFunc, std::ref(v2));
    f2();
    printNumbers(v2);

    std::cout << "generating v3" << std::endl;
    std::vector<double> v3;
    auto f3 = [&v3]() { myFunc(v3); };  //using a lambda
    f3();
    printNumbers(v3);

    return 0;
}