在std :: packaged_task中使用成员函数

时间:2013-06-24 22:54:08

标签: c++ multithreading c++11

我想做的事情应该很简单,但我不明白......

我想做的就是在后台启动一个类的成员函数 在某个特定的时间点。该功能的结果也应该是"外部"可用。所以我想在构造函数中准备任务(设置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(); }
};

提前致谢!

2 个答案:

答案 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));