c++ - boost::asio 与 boost::unique_future

标签 c++ boost-asio boost-thread

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

最佳答案

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

关于c++ - boost::asio 与 boost::unique_future,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22424715/

相关文章:

networking - boost::asio tcp async_accept 处理程序未被调用但同步连接工作正常

C++17 模板参数推导失败

c++ - boost::asio::async_write() 与 boost::asio::write()

c++ - boost asio在两个线程c++之间进行通信

C++清除队列和线程安全

c++ - 使用互斥量的正确方法

c++ - 检查一个数组是否以相反的顺序包含在另一个数组中,至少两次

c++ - C++ 转换时遇到问题

c++ - 关于在 C++ 中返回引用的函数的问题

c++ - 将仅移动函数参数传递给boost::thread构造函数