问题描述
std::future
、std::promise
和 std::thread
s
我正在尝试了解一些较新的 C++ 概念,例如 std::future
、std::promise
和 std::async
。
我想我非常了解期货和承诺是如何运作的。它们是类/对象的一种,可用于以方便的方式将数据传入和传出线程。总之,它们的工作方式如下:
- 创建一个定义要返回的数据类型的承诺
- 使用
promise.get_future()
为已创建的承诺创建未来
- 启动一个线程,将promise移动到线程函数中
- 父线程继续做其他工作,直到需要启动线程函数的结果,此时父线程通过调用
future.get()
等待结果。 - 如果结果已经被“设置”,父线程继续,否则它会休眠无限/无限/无限(?)时间
- 如果结果尚未“设置”,则子线程继续工作
- 子线程使用
promise.set_value()
设置承诺值 - 如果父线程正在休眠,这会提示将其唤醒
- 通常子线程会退出,父线程会调用
thread.join()
并继续工作
(我最喜欢的例子之一可以在这里找到:https://www.modernescpp.com/index.php/promise-and-future)
因此,promise future 构造提供了一种启动线程并返回结果的方法,同时在需要时在程序执行的点上保持父线程和子线程同步。
std::async
这就是我感到困惑的地方。我已经阅读了几个关于 std::async
的文档页面。让我困惑的是我通常将 future
与 promise
联系起来。但是当使用 std::async
时,任何时候都没有提到承诺。它是否被实现隐藏了?
以下是精选的文档页面:
- https://en.cppreference.com/w/cpp/thread/async
- https://www.cplusplus.com/reference/future/async/
- https://thispointer.com/c11-multithreading-part-9-stdasync-tutorial-example/
- Why should I use std::async?
- https://riptutorial.com/cplusplus/example/30411/std--future-and-std--async
- https://solarianprogrammer.com/2012/10/17/cpp-11-async-tutorial/
据我所知,std::async
执行以下操作:
- 启动一个线程,返回一个
std::future
对象 - (有不同的启动模式,可以“延迟”意味着在请求结果之前线程不会开始工作,“异步”意味着线程立即开始工作)
- 需要结果时,调用
future.get()
。 - 由于此过程中不涉及
promise
,因此我认为不可能使用promise
... 从future.get()
返回值 - 但是,一些示例表明返回类型由要使用
async
调用的函数定义。然后该值由future.get()
返回。所以可以返回一个值,但看不到std::promise
吗?
编辑:这是另一篇文章,详细介绍了期货、承诺、异步和打包任务。它提供了一些关于为什么您可能会使用不同选项的解释,但最后指出异步和使用 future/promise 启动线程之间的区别在于返回值可以在线程函数执行中的任何位置设置,而不仅仅是在最后通过 return
语句。
https://ncona.com/2018/02/futures-async-packaged_tasks-and-promises-in-c/
问题
- 为什么使用
async
而不是future
promise
对? -
async
是否只是用于启动线程同时将promise
从程序员的视野中隐藏起来的语法糖?
换句话说,我的问题是使用 async
来启动一个单独的线程和通过使用 std::thread
和 promise
显式使用 future
之间有什么区别。
- 它们在功能上一样吗?
解决方法
为什么使用 async
而不是 future
promise
对?
因为是一回事,而不是三+编排。或者因为您的实现是使用线程池完成的,而不是每次都创建一个新线程。或者因为您想要 deferred
或实现定义的启动策略。
async
是否只是用于启动线程同时将 promise
从程序员的视野中隐藏起来的语法糖?
在某些实现中,是的。在其他情况下,它可以在线程池线程上运行该函数。它只需要确保每次调用的可访问 thread_local
数据都是最新的。
它们在功能上是否相同?
从某种意义上说
template <typename F,typename... Args>
std::future<std::invoke_result_t<F,Args...>> async(F f,Args... args) {
std::promise<std::invoke_result_t<F,Args...>> prom;
auto fut = prom.get_future();
std::thread([p = std::move(prom)](F f,Args... args) { p.set_value_at_thread_exit(f(args...)); },f,args...).detach();
return fut;
}
大约是std::async
的作用吗?