kfm*_*e04 18 c++ c++11 stdthread
我正在尝试建立一些启发式方法来帮助我确定std::thread要使用的适当类.
据我了解,从最高级别(最简单到使用,但最不灵活)到最低级别,我们有:
我想我对何时使用前两个有一个很好的把握,但我仍然不清楚std::promise.
std::future与std::async调用一起,有效地将生成的回调/函数/ lambda转换为异步调用(根据定义,它立即返回).一个单一的消费者可以拨打std::future::get()阻止电话,以获得结果.
std::shared_future 只是一个允许多个消费者的版本.
如果要将std::future值与生成器回调绑定,但希望将实际调用推迟到以后(将任务关联到生成线程时),std::packaged_task则是正确的选择.但是现在,由于对应std::future于std::package_taskcan,在一般情况下,可以由多线程访问,我们可能必须小心使用a std::mutex.请注意std::async,在第一种情况下,我们不必担心锁定.
阅读了一些关于承诺的有趣链接,我想我理解它的机制以及如何设置它们,但我的问题是,你什么时候会选择使用其他三个承诺呢?
我正在寻找一个应用程序级别的答案,比如一个经验法则(填写上面的???),而不是链接中的答案(例如使用std :: promise来实现一些库机制),所以我可以更容易地解释如何为初级用户选择合适的类std::thread.
换句话说,这将是很好有什么我可以用做一个有用的例子std::promise是不能与其他机制来完成.
回答
A std::future是一种奇怪的野兽:一般来说,你不能直接修改它的值.
可以修改其价值的三个生产者是:
std::async通过异步回调,它将返回一个std::future实例.std::packaged_task,当传递给线程时,将调用其回调,从而更新std::future与之关联的实例std::packaged_task.此机制允许生成器的早期绑定,但稍后调用.std::promise,允许std::future通过其set_value()调用修改其关联.通过对变异a的这种直接控制std::future,如果有多个生成器(std::mutex必要时使用),我们必须确保设计是线程安全的.我认为SethCarnegie的答案是:
想一想的一个简单方法是,您可以通过返回值或使用promise来设置未来.未来没有固定的方法; 该功能由promise提供.
有助于澄清何时使用承诺.但我们必须记住,std::mutex可能有必要,因为承诺可能可以从不同的线程访问,具体取决于使用情况.
此外,大卫的罗德里格兹的答案也非常好:
通信通道的消费者端将使用std :: future来从共享状态使用数据,而生产者线程将使用std :: promise来写入共享状态.
但作为替代方案,为什么不简单地只使用一个std::mutexstl容器的结果,一个线程或生产者的线程池作用于容器?是什么用std::promise,而是给我买,除了一些额外的可读性VS结果的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() );
}
Run Code Online (Sandbox Code Playgroud)
Set*_*gie 17
你不选择使用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';
}
Run Code Online (Sandbox Code Playgroud)
版画
等待...完成!
结果是:7 8 9
期货与所有三个线程一起使用以获得其结果,并且a promise与第三个线程一起使用以future通过除返回值之外的方式来实现.此外,单个线程可以future通过promises 实现具有不同值的多个s,否则不能这样做.
想到它的一种简单方法是,您可以future通过返回值或使用a来设置promise.future没set办法; 该功能由promise.提供.根据情况允许,您可以根据需要选择.