问题描述
考虑以下代码:
#include <iostream>
#include <future>
#include <thread>
#include <chrono>
void func()
{
std::async(std::launch::async,[]{std::this_thread::sleep_for(std::chrono::milliseconds(1000)); });
}
int main()
{
std::cout << "start " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::Now().time_since_epoch()).count() << "ms\n";
func();
std::cout << "stop " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::Now().time_since_epoch()).count() << "ms\n";
return 0;
}
输出:
start 18737230ms
stop 18738230ms
我们可以看到func()
返回之前经过了1秒。但是,std::async(...);
中没有存储std :: future-即:auto f = std::async(...)
这似乎可行-但我正在徘徊这种机制的原理。如果我有std :: future(在我的小示例中为auto f),则当它超出范围时,它将整理线程-即等待1秒钟,然后将该线程丢弃在后台。
进一步测试:
int main() {
std::cout << "start " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::Now().time_since_epoch()).count() << "ms\n";
std::async(std::launch::async,[]{std::this_thread::sleep_for(std::chrono::milliseconds(1000)); });
std::cout << "stop1 " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::Now().time_since_epoch()).count() << "ms\n";
auto f = std::async(std::launch::async,[]{std::this_thread::sleep_for(std::chrono::milliseconds(1000)); });
std::cout << "stop2 " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::Now().time_since_epoch()).count() << "ms\n";
return 0;
}
给予:
start 4448133ms
stop1 4449133ms - 1 sec passed
stop2 4449133ms - no time passed
因此,这表明存储将来意味着线程并行运行。不存储将来意味着线程似乎必须运行完成-我猜这是因为临时的将来被创建和销毁了?
因此,我的结论是,如果您希望它并行运行(这就是重点),那么您不能只调用std::async(...)
而不存储std :: future-即使您不打算用未来。
嗯...我想我已经说服自己了! -但是我不是100%肯定我的推理正确-希望我有...
解决方法
如果通过std::future
创建了std::async
,则析构函数将等待任务结束。这并不意味着任务不会并行运行-它只是在变量作用域的末尾等待任务的结束。然而,它使用std::async
而不存储std::future
有点棘手,我通常建议将未来存储在某个地方,以避免令人讨厌的意外。看看at page about std::future
destructor(重点是我):
这些操作不会阻止共享状态变为就绪状态,除非在满足以下所有条件的情况下可能会阻止:共享状态是通过调用std :: async创建的,共享状态为尚未准备就绪,这是对共享状态的最后引用。