何时使用 std::launch::deferred?

问题描述 投票:0回答:4

安东尼·威廉书中的台词:

std::launch::deferred
表示函数调用是 推迟到未来调用
wait()
get()
时。

X baz(X&);

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

此代码相对于直接调用(

baz(ref(x))
)有什么好处或区别?

换句话说,这里拥有未来有什么意义?

c++ multithreading c++11 asynchronous
4个回答
19
投票

假设你有一个线程池。

线程池拥有一定数量的线程。说10.

当您添加任务时,它们会返回一个 future,并在池中排队。

池中的线程醒来,获取任务并处理它。

当该池中有 10 个任务等待队列中稍后的任务时,会发生什么?好吧,陷入僵局。

现在,如果我们从这个池中返回一个延期的未来会怎样。

当您等待这个延迟的未来时,它会醒来,检查任务是否完成。如果是,则完成并返回。

接下来,如果任务在队列中但尚未启动,它会从队列中窃取工作并

在那里运行它,然后返回。

最后,如果队列正在运行但尚未完成,它会执行更复杂的操作。 (通常有效的最简单版本是它会阻塞任务,但这并不能解决一些病态情况)。

无论如何,现在如果队列中的任务处于休眠状态,等待队列中尚未排队的另一个任务完成,我们仍然可以获得前进的进度。


它的另一个用途就不那么神秘了。假设我们有一些惰性值。

我们不计算它们,而是存储共享的 future 以及其中的计算步骤。现在任何需要它们的人都只需做一个

.get()

。如果已经计算过该值,则得到该值;否则,我们计算它,然后得到它。

后来,我们添加一个系统来在空闲或另一个线程中执行一些工作。这些在某些情况下取代了所说的延迟惰性期货,但在其他情况下则不然。


12
投票
我认为,主要的好处是它可以在不同的线程中执行 - 实际读取未来的线程。这允许在线程之间传输“工作单元” - 即线程 1 创建未来,而线程 2 对其调用

wait


0
投票
以我的观点。我读了

effective modern c++

规则35

Compared to thread-based programming, a task-based design spares you the travails of manual thread management
这意味着 std::launch::deferred 是一种更糟糕的情况,当操作系统无法为您分配新线程时,

baz

函数仍然可以工作,但它作为延迟任务运行,而不是像
pthread_create那样返回失败
 或像这样使用 std::thread 抛出异常:

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

// 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
https://godbolt.org/z/hYv7TW51q进行了测试


0
投票
您可以做的一件很酷的事情是控制异步任务在哪个线程上运行。

假设您想限制进程上的线程数。使用

async

 标志启动多个异步作业将使您失去可能拥有的任何控制权。有时这是可以的,但有时却不是。

但是使用

deffered

,您可以在主线程上启动一些任务,并在您控制的工作线程上,您可以调用 
get()
 来确定性地运行任务。

© www.soinside.com 2019 - 2024. All rights reserved.