通过引用 TBB 任务传递函数时不能 Return 值
Cannot Return Values When Passing Function by Reference To TBB Task
我对英特尔 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 失败?)并且我在 return 上得到一个空容器。
谁能看到我错过了什么?谢谢
我发现了几个与 tbb 无关的错误。
1) 您的 myFunc 使用范围不正确。它没有 return 一个索引,而是直接依次在向量中的每个值。您的代码将每个 double 转换为一个 int 并将其用作数组的索引,这就是您变得垃圾的原因。
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;
}
我对英特尔 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 失败?)并且我在 return 上得到一个空容器。
谁能看到我错过了什么?谢谢
我发现了几个与 tbb 无关的错误。
1) 您的 myFunc 使用范围不正确。它没有 return 一个索引,而是直接依次在向量中的每个值。您的代码将每个 double 转换为一个 int 并将其用作数组的索引,这就是您变得垃圾的原因。
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;
}