【问题标题】:boost::asio with boost::unique_futureboost::asio 与 boost::unique_future
【发布时间】:2021-11-07 11:21:45
【问题描述】:

根据http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/overview/cpp2011/futures.html,我们可以将 boost::asio 与std::future 一起使用。但是我找不到任何有关使用boost::unique_future 的信息,它具有更多功能,例如then()。如何使用?

【问题讨论】:

    标签: c++ boost-asio boost-thread


    【解决方案1】:

    Boost.Asio 只为异步操作提供一流的支持以返回 C++11 std::futurestackful coroutines 中的实际值。尽管如此,requirements on asynchronous operations 记录了如何自定义其他类型的返回类型,例如 Boost.Thread 的boost::unique_future。它需要:

    • handler_type 模板的特化。此模板用于根据异步操作的签名确定要使用的实际处理程序。
    • async_result 模板的特化。此模板用于确定返回类型并从处理程序中提取返回值。

    下面是一个最小的完整示例,演示了deadline_timer::async_wait() 返回boost:unique_future,并在一系列由.then() 组成的延续上执行基本计算。为了使示例简单,我选择仅将 handler_type 专门用于示例中使用的异步操作签名。如需完整参考,我强烈建议查看 use_future.hppimpl/use_future.hpp

    #include <exception> // current_exception, make_exception_ptr
    #include <memory> // make_shared, shared_ptr
    #include <thread> // thread
    #include <utility> // move
    
    #define BOOST_RESULT_OF_USE_DECLTYPE
    #define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
    
    #include <boost/asio.hpp>
    #include <boost/date_time/posix_time/posix_time.hpp>
    #include <boost/thread/future.hpp>
    
    /// @brief Class used to indicate an asynchronous operation should return
    ///        a boost::unique_future.
    class use_unique_future_t {};
    
    /// @brief A special value, similiar to std::nothrow.
    constexpr use_unique_future_t use_unique_future;
    
    namespace detail {
    
    /// @brief Completion handler to adapt a boost::promise as a completion
    ///        handler.
    template <typename T>
    class unique_promise_handler;
    
    /// @brief Completion handler to adapt a void boost::promise as a completion
    ///        handler.
    template <>
    class unique_promise_handler<void>
    {
    public:
      /// @brief Construct from use_unique_future special value.
      explicit unique_promise_handler(use_unique_future_t)
        : promise_(std::make_shared<boost::promise<void> >())
      {}
    
      void operator()(const boost::system::error_code& error)
      {
        // On error, convert the error code into an exception and set it on
        // the promise.
        if (error)
          promise_->set_exception(
              std::make_exception_ptr(boost::system::system_error(error)));
        // Otherwise, set the value.
        else
          promise_->set_value();
      }
    
    //private:
      std::shared_ptr<boost::promise<void> > promise_;
    };
    
    // Ensure any exceptions thrown from the handler are propagated back to the
    // caller via the future.
    template <typename Function, typename T>
    void asio_handler_invoke(
        Function function,
        unique_promise_handler<T>* handler)
    {
      // Guarantee the promise lives for the duration of the function call.
      std::shared_ptr<boost::promise<T> > promise(handler->promise_);
      try
      {
        function();
      }
      catch (...)
      {
        promise->set_exception(std::current_exception());
      }
    }
    
    } // namespace detail
    
    namespace boost {
    namespace asio {
    
    /// @brief Handler type specialization for use_unique_future.
    template <typename ReturnType>
    struct handler_type<
        use_unique_future_t,
        ReturnType(boost::system::error_code)>
    {
      typedef ::detail::unique_promise_handler<void> type;
    };
    
    /// @brief Handler traits specialization for unique_promise_handler.
    template <typename T>
    class async_result< ::detail::unique_promise_handler<T> >
    {
    public:
      // The initiating function will return a boost::unique_future.
      typedef boost::unique_future<T> type;
    
      // Constructor creates a new promise for the async operation, and obtains the
      // corresponding future.
      explicit async_result(::detail::unique_promise_handler<T>& handler)
      {
        value_ = handler.promise_->get_future();
      }
    
      // Obtain the future to be returned from the initiating function.
      type get() { return std::move(value_); }
    
    private:
      type value_;
    };
    
    } // namespace asio
    } // namespace boost
    
    int main()
    {
      boost::asio::io_service io_service;
      boost::asio::io_service::work work(io_service);
    
      // Run io_service in its own thread to demonstrate future usage.
      std::thread thread([&io_service](){ io_service.run(); });
    
      // Arm 3 second timer.
      boost::asio::deadline_timer timer(
          io_service, boost::posix_time::seconds(3));
    
      // Asynchronously wait on the timer, then perform basic calculations
      // within the future's continuations.
      boost::unique_future<int> result =
          timer.async_wait(use_unique_future)
            .then([](boost::unique_future<void> future){
               std::cout << "calculation 1" << std::endl;
               return 21;
            })
            .then([](boost::unique_future<int> future){
              std::cout << "calculation 2" << std::endl;
              return 2 * future.get();
            })
          ;
    
      std::cout << "Waiting for result" << std::endl;
      // Wait for the timer to trigger and for its continuations to calculate
      // the result.
      std::cout << result.get() << std::endl;
    
      // Cleanup.
      io_service.stop();
      thread.join();
    }
    

    输出:

    Waiting for result
    calculation 1
    calculation 2
    42
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-07
      • 1970-01-01
      • 2012-06-06
      • 2016-12-26
      • 1970-01-01
      • 1970-01-01
      • 2017-09-02
      相关资源
      最近更新 更多