Search code examples
c++c++11stdasyncstd-future

std::future returned from std::async hangs while going out of scope


I am using a combination of std::async and std::future from C++ 11. I am using to enforce a time_out on a certain activity that I do in my code which might take time as I try connecting to server.

Following is how the code is:

#include <future>
#include <chrono>

std::size_t PotentiallyLongRunningActivity() {
    using namespace std::chrono_literals;
    std::this_thread::sleep_for(10000s);
    return 10;
}

bool DoActivity() {

  bool activity_done = false;
  auto my_future_result(std::async(std::launch::async, []() {
      return PotentiallyLongRunningActivity(); //returns size_t
  }));

  std::future_status my_future_status = my_future_result.wait_for(std::chrono::milliseconds(800));
  if (my_future_status == std::future_status::timeout) {
      activity_done = false;
  }
  else if (my_future_status == std::future_status::ready) {
      if (my_future_result.valid() && my_future_result.get() > 0) {
          activity_done = true;
      }
  }

  return activity_done;
  //my_future_result hangs while exiting this method !!!
}

int main(int argc, char *argv[])
{
    DoActivity();
    return 0;
}

Things work fine in most of the cases. The future times out & is reported ready in many cases. But, Strange behavior I am observing is that in some cases the UI hangs because my_future_result when going out of scope hangs. I confirmed this by repeating the call to my_future_result.get() which never returns if called just before exiting the method.

How can I get around this ? Is there some way I cancel or delete or terminate the std::future ?


Solution

  • Taking from cppreference sample, only "the start", "f2 finished" and "the end" will get printed from this code (because f1 doesn't "hang"):

    #include <future>
    #include <thread>
    #include <iostream>
    
    int main() {
        using namespace std::literals;
    
        {
            std::packaged_task<int()> task([]() {
                std::this_thread::sleep_for(5s);
                std::cout << "f1 finished" << std::endl;
                return 42;
            });
            std::future<int> f1 = task.get_future();
            std::thread(std::move(task)).detach();
    
            std::future<int> f2 = std::async(std::launch::async, []() {
                std::this_thread::sleep_for(3s);
                std::cout << "f2 finished" << std::endl;
                return 42;
            });
    
            f1.wait_for(1s);
            f2.wait_for(1s);
            std::cout << "the start" << std::endl;
        }
    
        // std::this_thread::sleep_for(7s);
        std::cout << "the end" << std::endl;
    }
    

    For good discussion see: http://scottmeyers.blogspot.com.br/2013/03/stdfutures-from-stdasync-arent-special.html.

    C++ standard library gives no support for thread kill operations.

    Take care with threads you detach. Detachment per se is not "extremely bad", it may be useful in user terminable daemons for example, or if you have some other idea of orchestration and teardown. Otherwise, detach would have no point being provided by the standard library.