I am facing a situation where it would be nice to launch an std::async
operation totally asynchronously.
future<void> MyClass::MyAsyncFunc() {
std::future<void> f = std::async(...);
return f;
} // The future goes out of scope, will block.
The problem is that the function will block at the end if I don't save the future. I would like this not to happen.
This would prevent the std::future
to call its destructor at the end of the function's scope:
shared_ptr<future<void>> MyClass::MyAsyncFunc() {
auto shared_ftr = std::make_shared<std::future<void>>();
*shared_ftr = std::async([shared_ftr]() {...});
return shared_ftr;
}
Could this possibly work? What happens when I don't save the result in a variable?
Here is a fully fledged example. This pattern does work, I use it extensively with boost asio and asynchronous operations.
#include <chrono>
#include <iostream>
#include <future>
#include <memory>
#include <thread>
std::shared_ptr<std::future<int>> get_task()
// std::future<int> get_task() // rely on move, future supports move
{
auto f = std::make_shared<std::future<int>>();
//std::future<int> f = std::async(std::launch::async, [] {
*f = std::async(std::launch::async, [f] {
(void) f;
std::cout << "calculating" << std::endl;
for (int x = 0; x < 10; ++x)
std::this_thread::sleep_for( std::chrono::milliseconds( 200 ) );
std::cout << "done." << std::endl;
return 100;
});
return f;
}
int main(void)
{
std::cout << "getting task" << std::endl;
//auto f = get_task(); <-- the future is moved not copied, so there is no block here
get_task();
std::cout << "waiting" << std::endl;
// f.wait(); <-- now wait for it to complete...
// std::cout << " got: " << f.get() << std::endl;
// Wait for the truly async task to complete...
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
}
The only concern I'd express is that wait at the end, without capturing the future
(whether it's moved or via shared_ptr
), you have no way to stop the app from terminating before the task completes...
If you have some other way of ensuring continuation, then the shared_ptr
approach will work fine. Else, go with the moved future, it's cleaner...
future<void> MyClass::MyAsyncFunc() {
std::future<void> f = std::async(...
return f;
} //future out of scope, will block
and
shared_ptr<future<void>> MyClass::MyAsyncFunc() {
auto shared_ftr = std::make_shared<std::future<void>>();
*shared_ftr = std::async([]() {...});
return shared_ftr;
}
are equivalent. The later will work exactly when the former will.
The future in the function that goes out of scope is moved from and therefore can't block. The blocking most likely happens in the calling function, which you have not shown.
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