什么时候使用std :: promise比其他std :: thread机制更好?

时间:2013-01-11 17:40:57

标签: c++ c++11 stdthread

我正在尝试建立一些启发式方法来帮助我决定使用适当的std::thread类。

据我了解,从最高级别(最简单到使用,但最不灵活)到最低级别,我们有:

  1. std :: async with / std :: future(std :: shared_future)(当你想在一次性扔掉的生产者线程async上执行时)
  2. std :: packaged_task(当你想分配一个生产者,但是把这个调用推迟到线程)
  3. std :: promise(???)
  4. 我认为我对前两个何时使用有很好的把握,但我仍然不清楚std::promise

    std::futurestd::async调用一起,有效地将生成的回调/函数/ lambda转换为异步调用(根据定义,它立即返回)。一个单一的消费者可以拨打std::future::get()来阻止调用,以获得结果。

    std::shared_future只是一个允许多个消费者的版本。

    如果要将std::future值与生成器回调绑定,但希望将实际调用推迟到以后(将任务关联到生成线程时)std::packaged_task是正确的选择。但是现在,由于相应的std::futurestd::package_task,一般情况下可以通过多线程访问,我们可能需要注意使用std::mutex。请注意,对于std::async,在第一种情况下,我们不必担心锁定。

    阅读some interesting links on promise后,我想我了解其机制以及如何设置它们,但我的问题是,您何时会选择使用其他三种承诺? < / p>

    我正在寻找更多的应用程序级答案,比如经验法则(填写上面的???中的???),而不是链接中的答案(例如使用std: :承诺实现一些库机制),这样我就可以更轻松地解释如何为std::thread的初级用户选择合适的类。

    换句话说,有一个有用的例子可以说明我可以用std::promise做什么,不能用其他机制完成。

    ANSWER

    std::future是一个奇怪的野兽:一般来说,你不能直接修改它的值。

    可以修改其价值的三个生产者是:

    1. std::async通过异步回调,它将返回std::future个实例。
    2. std::packaged_task,当传递给线程时,将调用其回调,从而更新与std::future相关联的std::packaged_task实例。这种机制允许生成器的早期绑定,但后来的调用。
    3. std::promise,允许用户通过std::future调用修改其关联的set_value()。通过对std::future变异的直接控制,如果有多个生成器,我们必须确保设计是线程安全的(必须使用std::mutex)。
    4. 我认为SethCarnegie's answer

        

      一种简单的方法来思考它是你可以设定未来   返回值或使用promise。未来没有固定的方法;   该功能由promise提供。

      有助于澄清何时使用承诺。但我们必须记住,std::mutex可能是必要的,因为承诺可以从不同的线程访问,具体取决于使用情况。

      此外,David's Rodriguez's answer也非常出色:

        

      通信渠道的消费者端将使用std :: future   在生产者线程中使用来自共享状态的数据   将使用std :: promise写入共享状态。

      但作为替代方案,为什么不简单地在stl容器结果上使用std::mutex,并在生产者的一个线程或线程池中对容器进行操作?除了一些额外的可读性与stl容器结果之外,使用std::promise代替我买什么?

      std::promise版本中的控件似乎更好:

      1. wait()将阻止给定的未来,直到产生结果
      2. 如果只有一个生产者线程,则不需要互斥锁
      3. 以下google-test通过helgrind和drd,确认使用单个生产者,并且使用wait(),不需要互斥锁。

        TEST

        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() );
        }
        

2 个答案:

答案 0 :(得分:16)

您不选择使用其他人的promise ,而是使用promise 履行 a {{1} } 与其他人一起cppreference.com处的代码示例给出了使用全部四个的示例:

future

打印

  

等待...完成!

     

结果是:7 8 9

期货用于所有三个线程以获得结果,并且#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'; } 与第三个线程一起用于通过除返回值之外的方式来实现promise。此外,单个线程可以通过future来实现具有不同值的多个future,否则无法执行此操作。

一种简单的方法是,您可以通过返回值或使用promise来设置futurepromise没有future方法;该功能由set提供。根据情况允许,您可以选择所需的内容。

答案 1 :(得分:2)

当您有两个级别的异步时,您需要使用一个承诺。 例如:

void fun()
{
std::promise<int> p;
std::future<int> f = p.get_future();
std::future<void> f2;
auto f3 = std::async([&]{
   // Do some other computation
   f2 = std::async([&]{ p.set_value(42);});
   // Do some other work
});
   // Do some other work
   // Now wait for the result of async work;
std::cout << f.get();
   // Do some other work again 
// Wait for async threads to complete
f3.wait();
f2.wait();
}
相关问题