Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use std::launch::deferred?

Lines from Anthony William book:

std::launch::deferred indicates that the function call is to be deferred until either wait() or get() is called on the future.

X baz(X&);

auto f7 = std::async(std::launch::deferred, baz, std::ref(x)); //run in wait() or get()
//...
f7.wait();  //invoke deferred function

What could be the benefits or differences of this code over a direct call (baz(ref(x)) )?

In other words, what's the point of having future here?

like image 758
Saurav Sahu Avatar asked Sep 11 '17 19:09

Saurav Sahu


People also ask

What's the default launch flag for an async?

By default, std::async executed immediately its work package. The C++ runtime decides if the calculation happens in the same or a new thread. With the flag std::launch::async std::async will run its work package in a new thread.

Does STD async start new thread?

If the deferred flag is set, a callable function will be stored together with its arguments, but the std::async function will not launch a new thread. Moreover, the callable function will be executed if either future::get() or future::wait() is called.

What does STD async return?

async( std::launch policy, Function&& f, Args&&... args ); (since C++20) The function template async runs the function f asynchronously (potentially in a separate thread which might be a part of a thread pool) and returns a std::future that will eventually hold the result of that function call.

What is std :: future in C++?

std::future A future is an object that can retrieve a value from some provider object or function, properly synchronizing this access if in different threads. "Valid" futures are future objects associated to a shared state, and are constructed by calling one of the following functions: async. promise::get_future.


2 Answers

Suppose you have a thread pool.

The thread pool owns a certain number of threads. Say 10.

When you add tasks, they return a future, and they queue into the pool.

Threads in the pool wake up, grab a task, work on it.

What happens when you have 10 tasks in that pool waiting on a task later in the queue? Well, a deadlock.

Now, what if we return a deferred future from this pool.

When you wait on this deferred future it wakes up, checks if the task is done. If so, it finishes and returns.

Next, if the tasks is in the queue and not yet started, it steals the work from the queue and runs it right there, and returns.

Finally, if it is being run by the queue but not finished, it does something more complex. (the simplest version which usually works is that it blocks on the task, but that doesn't solve some pathological cases).

In any case, now if a task in the queue sleeps waits for another task in the queue to complete that isn't queue'd yet, we still get forward progress.


Another use of this is less arcane. Suppose we have some lazy values.

Instead of calculating them, we store shared futures with the calcuation steps in them. Now anyone who needs them just does a .get(). If the value has already been calculated, we get the value; otherwise, we calculate it, then get it.

Later, we add in a system to do some work on idle or in another thread. These replace said deferred lazy futures in some cases, but not in others.

like image 168
Yakk - Adam Nevraumont Avatar answered Oct 13 '22 17:10

Yakk - Adam Nevraumont


I think, the main benefit is that it might be executed in a different thread - the one which actually reads the future. This allows to transfer 'units of work' between threads - i.e. thread 1 creates the future, while thread 2 calls wait on it.

like image 11
SergeyA Avatar answered Oct 13 '22 18:10

SergeyA