您是否需要存储来自 std::async 的 std::future return 值?

Do you need to store the std::future return value from std::async?

考虑以下代码:

#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() returns 前 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::future 的情况下使用 std::async 有点棘手,我通常建议将未来存储在某个地方以避免令人讨厌的意外。看看at page about std::future destructor(强调我的):

these actions will not block for the shared state to become ready, except that it may block if all of the following are true: the shared state was created by a call to std::async, the shared state is not yet ready, and this was the last reference to the shared state.