I am a little bit confused by the std::async function.
The specification says:
asynchronous operation being executed "as if in a new thread of execution" (C++11 ยง30.6.8/11).
Now, what is that supposed to mean?
In my understanding, the code
std::future<double> fut = std::async(std::launch::async, pow2, num);
should launch the function pow2 on a new thread and pass the variable num to the thread by value, then sometime in the future, when the function is done, place the result in fut (as long as the function pow2 has a signature like double pow2(double);). But the specification states "as if", which makes the whole thing kinda foggy for me.
The question is:
Is a new thread always launched in this case? I hope so. I mean for me, the parameter std::launch::async makes sense in a way that I am explicitly stating I indeed want to create a new thread.
And the code
std::future<double> fut = std::async(std::launch::deferred, pow2, num);
should make lazy evaluation possible, by delaying the pow2 function call to the point where i write something like var = fut.get();. In this case the parameter std::launch::deferred, should mean that I am explicitly stating, I don't want a new thread, I just want to make sure the function gets called when there is need for it's return value.
Are my assumptions correct? If not, please explain.
Also, I know that by default the function is called as follows:
std::future<double> fut = std::async(std::launch::deferred | std::launch::async, pow2, num);
In this case, I was told that whether a new thread will be launched or not depends on the implementation. Again, what is that supposed to mean?
                        
The
std::async(part of the<future>header) function template is used to start a (possibly) asynchronous task. It returns astd::futureobject, which will eventually hold the return value ofstd::async's parameter function.When the value is needed, we call get() on the
std::futureinstance; this blocks the thread until the future is ready and then returns the value.std::launch::asyncorstd::launch::deferredcan be specified as the first parameter tostd::asyncin order to specify how the task is run.std::launch::asyncindicates that the function call must be run on its own (new) thread. (Take user @T.C.'s comment into account).std::launch::deferredindicates that the function call is to be deferred until eitherwait()orget()is called on the future. Ownership of the future can be transferred to another thread before this happens.std::launch::async | std::launch::deferredindicates 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::deferredis the default option, it means that the implementation of the template functionstd::asyncwill 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::futureholds 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 ofstd::futurereturned bystd::asyncwill thus block in its destructor.This misleading code can make you think that the
std::asynccalls are asynchronous, they are actually synchronous. Thestd::futureinstances returned bystd::asyncare temporary and will block because their destructor is called right whenstd::asyncreturns as they are not assigned to a variable.The first call to
std::asyncwill block for 2 seconds, followed by another 2 seconds of blocking from the second call tostd::async. We may think that the last call tostd::asyncdoes not block, since we store its returnedstd::futureinstance 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