The main method below launches two std::async
s. The future f in the main method is initially used to hold the future for the first async before being reassigned to the future of the second std::async. Both threads still appear to still complete on schedule which surprised me. Initially I (foolishly?) expected the first thread to be terminated/suspended on the reassignment of the future but was surprised to find it still lingering around.
Based on what I observed today I think I understand that the first async thread becomes detached at the future reassignment. I kept seeing segfaults during my ordeal today and I reckon this was simply the main thread terminating before the orphaned async processes could finish.
////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <future>
#include <thread>
#include <chrono>
#define WAIT_A_MINUTE std::this_thread::sleep_for(std::chrono::seconds(5));
int myBusyFunc() {
WAIT_A_MINUTE
std::cout<<"done!"<<std::endl;
return 71675;
}
std::string futureStatusStr(std::future<int>& f){
switch (f.wait_for(std::chrono::seconds(0))){
case std::future_status::ready: return "ready";
case std::future_status::timeout: return "timeout";
case std::future_status::deferred: return "deferred";
default:return "unknown";
};
}
void printFutureStatus(std::future<int>& f){
std::cout<<futureStatusStr(f)<<std::endl;
}
/////////////////////////////////////////////////////////////////////////////
int main()
{
std::future<int> f = std::async(std::launch::async,myBusyFunc);
printFutureStatus(f);
f = std::async(std::launch::async,myBusyFunc); // waits a minute
printFutureStatus(f);
f.wait(); // no wait required - ready
printFutureStatus(f);
return 0;
}
CodePudding user response:
This behavior is actually documented in std::future::~future. Excerpt from the documentation below:
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.
In practice, these actions will block only if the task’s launch policy is std::launch::async (see "Effective Modern C " Item 36), either because that was chosen by the runtime system or because it was specified in the call to std::async.
So, you can see that this result is not unexpected. When you reassign f
, the old object is destroyed and in that process the caller becomes blocked.
Taking the above into consideration, if you need to replace the future without blocking, you have a few options:
- Use deferred execution policy (
std::launch::deferred
) - Store the shared state before replacing:
auto g = f.share();
- If you want to discard or "abort" the old async call, introduce a mechanism to signal it for early-out.