What I want to do should be quite easy, but I don't get it...
All I want to do is to start a member function of a class in background at some certain point in time. The result of that function should also be "externally" available. So I want to prepare the task in the constructor (setting the future variable, ... ) and start it at some later point.
I tried to combine std::(packaged_task|async|future) but I didn't get it to work.
This snippet will not compile, but I think it shows what I want to do:
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(); }
};
Thanks in advance!
Just use std::bind()
:
#include <functional> // For std::bind()
foo() :
task(std::bind(&foo::do_something, this)),
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
result(task.get_future())
{
// ...
}
Moreover, you are doing the wrong thing here:
std::async as(std::launch::async, task)
// ^^
// Trying to declare a variable?
Since what you want is to call the std::async()
function, not to declare an object of a (non-existing) type std::async()
. So as a first step, change this into:
std::async(std::launch::async, task)
Notice, however, that this will not be enough to get the task running asynchronously: because of the odd behavior of std::async()
when the returned future is discarded, your task will always be executed as if you started it synchronously - the destructor of the returned future object will block until the completion of the operation. (*)
To solve this last problem, you can hold the returned future in your result
member variable (rather than assigning to result
the future returned by std::packaged_task::get_future()
upon construction):
result = std::async(std::launch::async, task);
// ^^^^^^^^
(*) I think that MSVC ignores this specification and actually executes the task asynchronously. So if you are working with VS2012, you may not suffer from this problem.
EDIT:
As correctly mentioned by Praetorian in his answer, the above would still be problematic, since a copy of the packaged_task
would be attempted at some point within the implementation of async()
. To work around this problem, you wrap your task
object in a reference wrapper by using std::ref()
.
do_something()
is a member function, which means it takes an implicit this
pointer as the first argument. You'll need to bind
the this
pointer, or create a lamda that invokes do_something
.
foo() :
task(std::bind(&foo::do_something, this)),
result(task.get_future())
{}
or
foo() :
task([this]{ return do_something(); }),
result(task.get_future())
{}
std::async as(std::launch::async, task);
std::async
is a function template, not a type. So the obvious change is
std::async(std::launch::async, task);
But that causes yet another error because somewhere within the guts of that call a copy of task
is attempted, but std::packaged_task
has a deleted copy constructor. You can fix that by using std::ref
, which will avoid the copy.
std::async(std::launch::async, std::ref(task));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With