Is it safe to never retrieve the result of a std::future from a std::packaged_task?
Asked Answered
B

1

7

Is it safe to create a std::future from a std::packaged_task, which executes on a separate thread, but not always retrieve its result?

#include <future>
#include <thread>

class Result {
  Result() {}
  ~Result() {}
};

void foo() {
  std::packaged_task<Result()> task(..);
  auto future = task.get_future();
  std::thread thread(std::move(task), ...);
  thread.detach();
  if (future.wait_for(std::chrono::milliseconds(timeout_ms)) == std::future_status::ready) {
    auto result = future.get();  <--- Task didn't take too long, retrieve future result
    ...
  }
}  <--- Task is taking too long, just abort and never call future.get()

It seems to work on Clang / libc++: ~Result() is called on the returned result by the std::packaged_task wether or not get() is eventually called on the std::future, but since I couldn't find anything in the C++ docs about this usage pattern, I'd like to make sure it's officially supported.

Bamby answered 31/5, 2016 at 2:55 Comment(0)
C
0

It depends.... on what you consider as safe for your program.
For the context you have shown, it's safe as in:

  • It does not block when the future is destroyed before doing a get on it . If the future was created using std::async and if you do not call get on it before it is destroyed, the it would have blocked till the result was available.
    Check out more on this here: http://en.cppreference.com/w/cpp/thread/future/~future

these actions will not block for the shared state to become ready, except that it may block if all of the following are true: the shared state was created by a call to std::async, the shared state is not yet ready, and this was the last reference to the shared state.

Now, what if the Result class was holding a non-owning memory (for whatever reason) or some other resource which needs to be manually freed up. In that case, the correctness of your code becomes questionable. A better thing to do would be to dispatch it to some background thread for slow moving tasks.

Culberson answered 31/5, 2016 at 6:59 Comment(2)
I had noticed the blocking behavior with std::async indeed, that's why I switched to std::packaged_task. I'm not sure what you mean by correctness of your code becomes questionable? As long as ~Result() is guaranteed to be called either way by the shared state, then what could go wrong?Bamby
Indeed you are correct if your Result class is designed to own the memory. But seldom is the case that you would have to keep non owning data. In such cases forgetting to call get_future would be incorrect. If it's done with purpose (as in your example) then it's probably ok if resource is taken care by RAII.Culberson

© 2022 - 2024 — McMap. All rights reserved.