boost::asio 与 boost::unique_future

Posted

技术标签:

【中文标题】boost::asio 与 boost::unique_future【英文标题】:boost::asio with boost::unique_future 【发布时间】:2014-04-20 21:47:34 【问题描述】:

根据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()。如何使用?

【问题讨论】:

【参考方案1】:

Boost.Asio 只为异步操作提供一流的支持以返回 C++11 std::future 或 stackful 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

【讨论】:

以上是关于boost::asio 与 boost::unique_future的主要内容,如果未能解决你的问题,请参考以下文章

std::bind 是不是应该与 boost::asio 兼容?

boost asio 学习

使用 boost::asio::async_wait_until 和 boost::asio::streambuf

将 fork() 与 boost::asio::ip::tcp::iostream 一起使用是不是安全?

等到发布到 boost::asio::thread_pool 的作业(与所有作业完全相反)完成?

如何将 boost.Asio 与 MJPEG 一起使用?