我正在尝试建立一些启发式方法,以帮助我确定要使用的适当std::thread
类。
据我了解,从最高级别(使用最简单,但最不灵活)到最低级别,我们有:
我认为我在前两个何时使用时对有一定的了解,但是对于
std::promise
仍然不清楚。std::future
和std::async
调用有效地将产生的回调/functor/lambda转换为异步调用(根据定义,该调用立即返回)。单个消费者可以调用std::future::get()
(阻塞调用)来返回结果。std::shared_future
只是允许多个使用者使用的版本。如果您想将
std::future
值与生产者回调绑定(bind),但想将实际调用推迟到以后(当您将任务关联到生成线程时),std::packaged_task
是正确的选择。但是现在,由于一般情况下,可以通过多线程访问std::future
对应的std::package_task
,因此我们可能必须小心使用std::mutex
。注意,在第一种情况下,使用std::async
,我们不必担心锁定。阅读some interesting links on promise之后,我想我了解它的机制以及如何设置它们,但是我的问题是,您何时选择在其他三个方面使用promise?
我正在寻找一个应用程序级别的答案,例如经验法则(填写上面3中的???),而不是链接中的答案(例如,使用std::promise实现一些库)机制),因此我可以更轻松地向
std::thread
的初学者解释如何选择适当的类。换句话说,最好有一个有用的示例说明我可以用
std::promise
做什么,而无法用其他机制完成。答案
std::future
是一种奇怪的野兽:通常,您不能直接修改其值。可以修改其值的三个生产者是:
通过异步回调实现
std::async
,它将返回一个std::future
实例。 std::packaged_task
,当传递给线程时,它将调用其回调,从而更新与该std::future
关联的std::packaged_task
实例。该机制允许早期绑定(bind)生产者,但稍后进行调用。 std::promise
,它允许一个人通过其std::future
调用来修改其关联的set_value()
。通过这种对std::future
进行突变的直接控制,如果有多个生产者(必须使用std::mutex
),我们必须确保设计是线程安全的。 我认为SethCarnegie's answer:
An easy way to think of it is that you can either set a future by returning a value or by using a promise. future has no set method; that functionality is provided by promise.
帮助阐明何时使用 promise 。但是我们必须记住,可能需要
std::mutex
,因为可以根据用途从不同的线程访问promise。另外,David's Rodriguez's answer也很出色:
The consumer end of the communication channel would use a std::future to consume the datum from the shared state, while the producer thread would use a std::promise to write to the shared state.
但是,作为一种替代方法,为什么不仅仅在STL结果容器上使用
std::mutex
,并使用一个线程或生产者线程池对容器进行操作呢?使用std::promise
可以代替我,除了具有额外的可读性和STL容器之外,还可以给我带来什么?该控件在
std::promise
版本中似乎更好:以下google-test通过helgrind和drd,确认使用单个生产者并使用wait()不需要互斥体。
测试
static unsigned MapFunc( std::string const& str )
{
if ( str=="one" ) return 1u;
if ( str=="two" ) return 2u;
return 0u;
}
TEST( Test_future, Try_promise )
{
typedef std::map<std::string,std::promise<unsigned>> MAP;
MAP my_map;
std::future<unsigned> f1 = my_map["one"].get_future();
std::future<unsigned> f2 = my_map["two"].get_future();
std::thread{
[ ]( MAP& m )
{
m["one"].set_value( MapFunc( "one" ));
m["two"].set_value( MapFunc( "two" ));
},
std::ref( my_map )
}.detach();
f1.wait();
f2.wait();
EXPECT_EQ( 1u, f1.get() );
EXPECT_EQ( 2u, f2.get() );
}
最佳答案
您没有选择使用promise
来代替其他代码,而是使用promise
与其他代码一起实现future
。 cppreference.com上的代码示例给出了使用全部四个示例:
#include <iostream>
#include <future>
#include <thread>
int main()
{
// future from a packaged_task
std::packaged_task<int()> task([](){ return 7; }); // wrap the function
std::future<int> f1 = task.get_future(); // get a future
std::thread(std::move(task)).detach(); // launch on a thread
// future from an async()
std::future<int> f2 = std::async(std::launch::async, [](){ return 8; });
// future from a promise
std::promise<int> p;
std::future<int> f3 = p.get_future();
std::thread( [](std::promise<int>& p){ p.set_value(9); },
std::ref(p) ).detach();
std::cout << "Waiting...";
f1.wait();
f2.wait();
f3.wait();
std::cout << "Done!\nResults are: "
<< f1.get() << ' ' << f2.get() << ' ' << f3.get() << '\n';
}
版画Waiting...Done!
Results are: 7 8 9
future 与所有三个线程一起使用以获取其结果,而
promise
与第三个线程一起使用以通过返回值以外的方式实现future
。同样,单个线程可以通过future
来实现多个具有不同值的promise
,否则它将无法完成。一种简单的想法是,您可以通过返回值或使用
future
来设置promise
。 future
没有set
方法;该功能由promise
提供。您可以根据情况选择所需的内容。
关于c++ - 什么时候在其他std::thread机制上使用std::promise是个好主意?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14283703/