I have just stumbled accross std::jthread: https://en.cppreference.com/w/cpp/thread/jthread
Which seems to be solving the same problem as std::async/future has already solved (although you may need to force the behaviour of async std::async(std::launch::async, ...
to run immediately.
So my question is what is the point of using one over the other? - is there some difference? is jthread a wrapper of async/future?
CodePudding user response:
Abstractly, they are very similar. Assume that one uses std::launch::async
and one does not call std::jthread::detach
. They both accept synchronous functions and run them concurrently with the current thread of execution. They both provide a way to wait on the completion: std::future::get
or std::jthread::join
. They both implicitly and automatically perform the wait on destruction.
The differences are more about the particular details and guarantees.
It should be noted that std::jthread
was added as a fix for std::thread
. std::thread
was added in C 11 alongside std::async
, and the same question is valid for these. So, std::async
had not "already" solved the problem, they were released together, as far as is relevant for this question. The problem with std::thread
was that it required the user to always join
or detach
the thread, detach
was always wrong, and if the user forgot to join
, the program would terminate.
There is a meaningful difference in how values are returned. std::async
must implicitly allocate a shared location for the return value. That isn't always necessary: sometimes you don't need a value, or sometimes you know that the asynchronous operation will complete before the current function returns (so, a captured stack variable suffices).
There is a meaningful difference between std::future
s returned from std::async
and those constructed some other way. The ones returned from std::async
block on destruction, which is not the typical behavior. This complicates both the implementation and the mental model of std::future
.
There is a meaningful difference in how exceptions are handled. Exceptions are propagated back with std::async
.
Therefore, the comments are spot on. std::async
can easily be implemented with std::thread
or std::jthread
so it is at a higher level. But conversely, std::async
makes implicit choices which are not always optimal.