Будет ли этот асинхронный трюк работать, или состояние будет зависать, когда я получу к нему доступ?

Я сталкиваюсь с ситуацией, когда было бы неплохо запустить std::async операция полностью асинхронная.

future<void> MyClass::MyAsyncFunc() {
std::future<void> f = std::async(...);
return f;
}  // The future goes out of scope, will block.

Проблема в том, что функция будет заблокирована в конце, если я не сохраню будущее. Я бы хотел, чтобы этого не произошло.

Это предотвратит std::future вызвать деструктор в конце области действия функции:

shared_ptr<future<void>> MyClass::MyAsyncFunc() {
auto shared_ftr = std::make_shared<std::future<void>>();
*shared_ftr = std::async([shared_ftr]() {...});
return shared_ftr;
}

Может ли это сработать? Что происходит, когда я не сохраняю результат в переменной?

13

Решение

Вот полноценный пример. Этот шаблон работает, я широко его использую с boost asio и асинхронными операциями.

#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));
}

Единственное, что я хотел бы выразить, — это ждать в конце, не захватывая future (будь то перемещено или через shared_ptr), у вас нет способа остановить завершение приложения до завершения задачи …

Если у вас есть какой-то другой способ обеспечения продолжения, то shared_ptr подход будет работать нормально. Иначе, иди с перенесенным будущим, оно чище …

6

Другие решения

future<void> MyClass::MyAsyncFunc() {
std::future<void> f = std::async(...
return f;
} //future out of scope, will block

а также

shared_ptr<future<void>> MyClass::MyAsyncFunc() {
auto shared_ftr = std::make_shared<std::future<void>>();
*shared_ftr = std::async([]() {...});

return shared_ftr;
}

являются эквивалент. Последний будет работать именно тогда, когда первый будет.

Будущее в функции, которая выходит из области видимости, перемещено и поэтому не может блокироваться. Скорее всего, блокировка происходит в призвание функция, которую вы не показали.

2