我想做的事情应该很简单,但我不明白......
我想做的就是在后台启动一个类的成员函数 在某个特定的时间点。该功能的结果也应该是"外部"可用。所以我想在构造函数中准备任务(设置future变量,...)并在稍后的某个时间启动它。
我尝试将std ::(packaged_task | async | future)结合起来,但我没有让它工作。
此代码段无法编译,但我认为它显示了我想要做的事情:
class foo {
private:
// This function shall run in background as a thread
// when it gets triggered to start at some certain point
bool do_something() { return true; }
std::packaged_task<bool()> task;
std::future<bool> result;
public:
foo() :
task(do_something), // yes, that's wrong, but how to do it right?
result(task.get_future())
{
// do some initialization stuff
.....
}
~foo() {}
void start() {
// Start Task as asynchron thread
std::async as(std::launch::async, task); // Also doesn't work...
}
// This function should return the result of do_something
bool get_result() { return result.get(); }
};
提前致谢!
答案 0 :(得分:9)
只需使用std::bind()
:
#include <functional> // For std::bind()
foo() :
task(std::bind(&foo::do_something, this)),
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
result(task.get_future())
{
// ...
}
此外,你在这里做错了:
std::async as(std::launch::async, task)
// ^^
// Trying to declare a variable?
因为你想要的是调用std::async()
函数,而不是声明一个(不存在的)类型std::async()
的对象。因此,作为第一步,将其更改为:
std::async(std::launch::async, task)
但请注意,这不足以使任务异步运行:由于std::async()
在丢弃返回的未来时出现奇怪的行为,因此您的任务将始终执行,就像< / em>你同步启动它 - 返回的future对象的析构函数将阻塞,直到操作完成。 (*)
要解决最后一个问题,您可以在result
成员变量中保留返回的未来(而不是在构建时将result
指定的未来分配给std::packaged_task::get_future()
):
result = std::async(std::launch::async, task);
// ^^^^^^^^
(*)我认为 MSVC忽略了这个规范,实际上是异步执行任务。因此,如果您正在使用VS2012,您可能不会遇到此问题。
修改强>
As correctly mentioned by Praetorian in his answer,上述内容仍有问题,因为packaged_task
的副本会在async()
的实施过程中的某个时刻尝试。要解决此问题,请使用std::ref()
将task
对象包装在引用包装中。
答案 1 :(得分:4)
do_something()
是一个成员函数,这意味着它将一个隐式this
指针作为第一个参数。您需要bind
this
指针,或者创建一个调用do_something
的lamda。
foo() :
task(std::bind(&foo::do_something, this)),
result(task.get_future())
{}
或
foo() :
task([this]{ return do_something(); }),
result(task.get_future())
{}
std::async as(std::launch::async, task);
std::async
是一个函数模板,而不是一个类型。所以明显的变化是
std::async(std::launch::async, task);
但是这会导致另一个错误,因为在该调用的内部某处尝试了task
的副本,但std::packaged_task
有一个已删除的复制构造函数。您可以使用std::ref
来解决此问题,这将避免复制。
std::async(std::launch::async, std::ref(task));