std::future::get() 或 std::future::wait() 是 std::thread::join() 的替代品吗?

Is std::future::get() or std::future::wait() a replacement for std::thread::join()?

在调用了未来的 future.get()/future.wait() 之后,线程会像 thread.join() 那样加入吗?我可以加入一个只使用它的 future 的线程而不直接访问该线程吗?

如评论中所述,std::futurestd::thread 没有任何关系。因此,只有在使用 std::thread 时才使用 std::thread::join,如果使用 std::future.

,则使用 std::future::get/std::future::wait

std::future 引擎盖下,有一个线程池接受作业并以智能方式分发它。

使用 future 时,您不能 100% 确定是否创建了实际的新线程。例如,当您使用 std::launch::deferred 执行策略创建 future 时,执行非常串行。

引用标准:

std::launch::deferred: the task is executed on the calling thread the first time its result is requested (lazy evaluation)


实际上,当您使用 std::launch::async 执行策略创建 future 时,大多数情况下都会启动一个新线程。使用 gcc 10 检查生成的代码,我可以清楚地看到 thread::join 被调用:

std::__future_base::_Async_state_commonV2::_M_complete_async():
        pushq   %rbp
        movq    %rsp, %rbp
        //more assembly maddness
        call    std::__future_base::_Async_state_commonV2::_M_join()

这又会导致 thread::join() 调用。

std::__future_base::_Async_state_commonV2::_M_join():
        pushq   %rbp
        movq    %rsp, %rbp
        subq    , %rsp
        movq    %rdi, -40(%rbp)
        movq    -40(%rbp), %rcx
        addq    , %rcx
        movq    %rcx, -24(%rbp)
        movl    $std::thread::join(), %eax
        ...

Is std::future::get() or std::future::wait() a replacement for std::thread::join()?

不,这些是不同的东西。

std::future是一个同步工具。它是一个 value 的包装器,它不能立即可用,但将会可用。它用于从异步操作(可以 运行 在另一个线程中)传递数据。在引擎盖下,它包含一个信号量,如果需要,get() 会在其上等待。

另一方面,

A std::thread 表示实际执行线程。它可以产生多个结果,因此在其生命周期内提供多个 std::promises。它应该这样做,因为启动和加入线程是一个相对重量级的操作,比等待未来要重得多。这就是为什么人们应该更喜欢重用线程,将异步操作发布到线程池并等待它们的结果(std::packaged_task 是一个有用的抽象)。

线程不会在 std::future::get() 后立即退出,即使设置 promise 是它做的最后一件事。这些是不相关的事件。