et_future(); // 得到pt的future
在这时,我们知道future对象fut没有引用由std::async调用的产生的shared state,所以它的析构函数将会表现出正常的行为。
一旦std::packaged_task对象pt被创建,它就会被运行在线程中。(它也可以借助std::async调用,但是如果你想要用std::async运行一个任务,没有理由创建一个std::packaged_task对象,因为std::async能做std::packaged_task能做的任何事情。)
std::packaged_task不能被拷贝,所以当把pt传递给一个std::thread构造函数时,它一定要被转换成一个右值(借助std::move——看条款23):
std::thread t(std::move(pt)); // 在t上运行pt
这个例子让我们看到了一些future正常析构行为,但如果把这些语句放在同一个块中,就更容易看出来:
{ // 块开始 std::packaged_task
pt(calcValue); auto fut = pt.get_future(); std::thread t(std::move(pt)); ... // 看下面 } // 块结束
这里最有趣的代码是“…”,它在块结束之前,t创建之后。这里有趣的地方是在“…”中,t会发生什么。有3个基本的可能:
t什么都没做。在这种情况下,t在作用域结束时是可连接的(joinable),这将会导致程序终止(看条款37)。 t进行了join操作。在这种情况下,fut就不需要在析构时阻塞了,因为代码已经join了。 t进行了detach操作。在这种情况下,fut就不需要在析构时detach了,因为代码已经做了这件事了。
换句话说,当你shared state对应的future是由std::packaged_task产生的,通常不需要采用特殊析构策略,因为操纵运行std::packaged_task的std::thread的代码会在终止、join、detach之间做出决定。
*需要记住的2点:
future的析构函数通常只是销毁future的成员变量。 最后一个引用shared state(它是在借助std::aysnc创建了一个非推迟任务时产生)的future会阻塞到任务完成。