std::thread does not provide an easy way to return a
value from a thread. We could do it via references but this approach
unnecessarily shares data between multiple threads and looks a bit cumbersome.
Another approach would be to use a condition variable from the previous article. The condition variable is associated with a condition and synchronizes threads when the condition is fulfilled. In our case, the condition would be the end of a thread and the result would be synchronized between the main and the spawned thread. It looks like that this is a special type of condition. Using the condition variable for returning from a thread seems like a big overhead. It must be some easier way to do it.
Thankfully, the standard template library provides a mechanism to return from a thread without using condition variables. The solution is to use the futures.
Instead of creating a thread with a function and its arguments, we create a future representation of the result. In other words: if we have a function
we can create a thread.
But now, we can not get the result of the function. Instead,
std::async creates a future representation of the result
The template argument of the future is the return type of the function. In our
case, the template argument of the
return type is
We can get the result of the function by calling the
member function of the future.
.get() blocks current thread until the
complicated_computation returns the result.
Lets look at another example.
The story is simple. A couple, wife and husband, are going on a picnic tomorrow. The wife would like to know what will be the temperature of the weather. Therefore, she asks her husband to look it up.
Again, keep in mind that the persons represent different threads (tasks).
We need to include
<future> in order to use them. Here is
also one helper function, which pauses current thread for a given number of
milliseconds. The purpose of this function is to better understand the execution
of the code.
The next section of the code represents the actions of the husband.
It prints some information and eventually returns
The last part of the code is the main function.
The interesting parts of the code are construction of the
std::future object by calling the
std::async and acquisition of the temperature by calling the
.get() member function of the future.
When we run the example, we might get the following result.
But this looks strange. The
temperature() started to run when
.get() member function of the
was called. Therefore, the execution is not asynchronous.
The readers might think: “Jaka, did you mislead us? The
std::async doesn’t create a new thread!” Well, I did mislead
you a little. The compiler can choose whether to run the function in a new
thread or synchronously. But don’t despair. We can explicitly set our compiler
to use either one of the policies.
std::async has an optional first argument which
determines how the
std::async computes the value of the
future. We can choose between three values for the first argument.
The first value, which enables asynchronous evaluation, is
std::launch::async . This means that the computation
temperature()) will always be in a new thread. Our
code would then look like
and the next figure describes the timeline of the program in this case.
The second value is
std::launch::deferred which enables lazy
evaluation. This means that the computation will be deferred until the
.get() member function of the future will be called. This
happened in our example above.
The advantage of this option is that the computation might never occur, if we
never call the
.get() member function. For this option, our
code would look like:
The next figure describes the timeline of the program in this case.
If we don’t provide the optional argument, the compiler will use the default
value which is
std::launch::async | std::launch::deferred.
This means that either one of the upper two cases might happen. In the example
above, we didn’t provide the optional argument and the implementation chose
We learned how to return a value from a thread with futures and
std::async has two options.
It can run a function in a separate thread.
Or it can defer the execution of the function until the
.get()member function is called.