当未存储返回值时,std::async 不会产生新线程
Posted
技术标签:
【中文标题】当未存储返回值时,std::async 不会产生新线程【英文标题】:std::async won't spawn a new thread when return value is not stored 【发布时间】:2012-02-28 21:59:07 【问题描述】:考虑一下我有 Lamba foo
,它只是做一些事情,不需要返回任何东西。
当我这样做时:
std::future<T> handle = std::async(std::launch::async, foo, arg1, arg2);
一切运行良好,lamba 将在新线程中生成。
但是,当我不存储std::async
返回的std::future
时,foo 将在主线程中运行并阻塞它。
std::async(std::launch::async, foo, arg1, arg2);
我在这里错过了什么?
【问题讨论】:
也许async
返回的future
会被立即销毁。如果future
的析构函数内部有隐式等待,我不会感到惊讶。
【参考方案1】:
来自just::thread
documentation:
如果策略是
std::launch::async
,则在其自己的线程上运行INVOKE(fff,xyz...)
。返回的std::future
将在此线程完成时准备就绪,并将保存返回值或函数调用引发的异常。与返回的std::future
的异步状态相关联的最后一个未来对象的析构函数将阻塞,直到未来准备好。
在
std::async(std::launch::async, foo, arg1, arg2);
返回的未来不会被分配到任何地方,并且它的析构函数会阻塞,直到 foo
完成。
【讨论】:
【参考方案2】:我想添加一个链接,指向 Herb Sutter 在 async and ~future 上发表的一篇文章,他认为期货永远不应该阻塞。
【讨论】:
这不是一篇文章,而是一个提案。除此之外,是的,阻止~future()
是一个错误。
~future() 默认情况下实际上并不阻塞。它仅在从 std::async 返回时才阻塞,因为 async 将阻塞状态分配给 future 并且 ~future() 必须释放它。
> async 将阻塞状态分配给未来...... @WojciechCierpucha 但这是为什么呢?【参考方案3】:
为什么要屏蔽?
std::async();
返回std::future
临时对象 临时对象立即销毁,调用析构函数。std::future
析构函数正在阻塞。这很糟糕而且很麻烦。
为什么分配是好的?
通过分配给变量,返回的对象不会立即销毁,而是稍后,直到调用代码的范围结束。
代码示例:main1
可以。 main2
和 main3
等效地阻塞了主线程。
void forever()
while (true);
void main1()
std::future<void> p = std::async(std::launch::async, forever);
std::cout << "printing" << std::endl; // can print, then forever blocking
void main2()
std::async(std::launch::async, forever);
std::cout << "printing" << std::endl; // forever blocking first, cannot print
void main3()
std::future<void> p = std::async(std::launch::async, forever);
std::cout << "printing" << std::endl; // forever blocking first, cannot print
看看cplusplus.com
std::async 的返回值 启动::选择async时,将来返回的未来链接到 创建的线程结束,即使它的共享状态从未被访问过: 在这种情况下,它的析构函数与 fn 的返回同步。 因此,对于异步,不应忽略返回值 行为,即使 fn 返回 void。
【讨论】:
以上是关于当未存储返回值时,std::async 不会产生新线程的主要内容,如果未能解决你的问题,请参考以下文章
C++11 多线程std:: async与std::thread的区别