The std::async
(part of the <future>
header) function template is used to start a (possibly) asynchronous task. It returns a std::future
object, which will eventually hold the return value of std::async
's parameter function.
When the value is needed, we call get() on the std::future
instance; this blocks the thread until the future is ready and then returns the value. std::launch::async
or std::launch::deferred
can be specified as the first parameter to std::async
in order to specify how the task is run.
std::launch::async
indicates that the function call must be run on its own (new) thread. (Take user @T.C.'s comment into account).
std::launch::deferred
indicates that the function call is to be deferred until either wait()
or get()
is called on the future. Ownership of the future can be transferred to another thread before this happens.
std::launch::async | std::launch::deferred
indicates that the implementation may choose. This is the default option (when you don't specify one yourself). It can decide to run synchronously.
Is a new thread always launched in this case?
From 1., we can say that a new thread is always launched.
Are my assumptions [on std::launch::deferred] correct?
From 2., we can say that your assumptions are correct.
What is that supposed to mean? [in relation to a new thread being launched or not depending on the implementation]
From 3., as std::launch::async | std::launch::deferred
is the default option, it means that the implementation of the template function std::async
will decide whether it will create a new thread or not. This is because some implementations may be checking for over scheduling.
WARNING
The following section is not related to your question, but I think that it is important to keep in mind.
The C++ standard says that if a std::future
holds the last reference to the shared state corresponding to a call to an asynchronous function, that std::future's destructor must block until the thread for the asynchronously running function finishes. An instance of std::future
returned by std::async
will thus block in its destructor.
void operation()
{
auto func = [] { std::this_thread::sleep_for( std::chrono::seconds( 2 ) ); };
std::async( std::launch::async, func );
std::async( std::launch::async, func );
std::future<void> f{ std::async( std::launch::async, func ) };
}
This misleading code can make you think that the std::async
calls are asynchronous, they are actually synchronous. The std::future
instances returned by std::async
are temporary and will block because their destructor is called right when std::async
returns as they are not assigned to a variable.
The first call to std::async
will block for 2 seconds, followed by another 2 seconds of blocking from the second call to std::async
. We may think that the last call to std::async
does not block, since we store its returned std::future
instance in a variable, but since that is a local variable that is destroyed at the end of the scope, it will actually block for an additional 2 seconds at the end of the scope of the function, when local variable f is destroyed.
In other words, calling the operation()
function will block whatever thread it is called on synchronously for approximately 6 seconds. Such requirements might not exist in a future version of the C++ standard.
Sources of information I used to compile these notes:
C++ Concurrency in Action: Practical Multithreading, Anthony Williams
Scott Meyers' blog post: http://scottmeyers.blogspot.ca/2013/03/stdfutures-from-stdasync-arent-special.html