c++ - 什么时候在其他std::thread机制上使用std::promise是个好主意?

标签 c++ c++11 stdthread

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

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

  • std::async with/std::future(std::shared_future)(当您想一次性使用生产者线程异步执行时)
  • std::packaged_task(当您想分配生产者,但将调用推迟到线程时)
  • std::promise(???)

  • 我认为我在前两个何时使用时对有一定的了解,但是对于std::promise仍然不清楚。
    std::futurestd::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版本中似乎更好:
  • wait()将在给定的将来阻塞,直到产生结果为止
  • 如果只有一个生产者线程,则不需要互斥

  • 以下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与其他代码一起实现futurecppreference.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来设置promisefuture没有set方法;该功能由promise提供。您可以根据情况选择所需的内容。

    关于c++ - 什么时候在其他std::thread机制上使用std::promise是个好主意?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14283703/

    相关文章:

    c++ - 是否可以确定(在运行时)功能是否已实现?

    c++ - 将天数添加到日期 C++

    c++ - Mingw编译错误使用

    c++ - 如何在 C++11 中使用 tinyutf8 在另一个 utf8_string 中查找 utf8_string?

    c++ - vector 会导致错误共享吗

    c++ - 自动更改 C++11 中的含义;请删除它这是什么意思?

    C++ 在调用 std::unique_lock 等待之前解锁 std::mutex

    c++ - 问题 - 返回文本文件排列的递归函数

    c++ - std::thread 通过引用传递调用复制构造函数

    c++ - 有没有办法使用对象及其非空参数列表调用运算符来生成 std​​::thread ?