简体   繁体   中英

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?

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.

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 - ie thread 1 creates the future, while thread 2 calls wait on it.

in my point of view. I read effective modern c++ rule 35

Compared to thread-based programming, a task-based design spares you the travails
of manual thread management

it means std::launch::deferred is a worse case when the OS have no ability to allocate a new thread for you however, the baz function still work but it run as a deferred task instead of returning failed like pthread_create or throw exception with std::thread like this:

terminate called after throwing an instance of 'std::system_error'
  what():  Resource temporarily unavailable

conclusion:

// same thread with called.
    std::async(std::launch::deferred, bax,..) = baz() 

// create a new thread to run baz(..) in case of OS have ability to allocate a new thread, otherwise same above 
    std::async(baz, ...) = std::async(std::launch::deferred| std::launch::async , baz, ...) != baz() ;

https://man7.org/linux/man-pages/man3/pthread_create.3p.html
tested at https://godbolt.org/z/hYv7TW51q

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM