您是否需要存储std :: async的std :: future返回值?

问题描述

考虑以下代码

#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创建的,共享状态为尚未准备就绪,这是对共享状态的最后引用。