取消的 boost::asio 处理程序的处理程序什么时候开始运行?

Ste*_*udi 3 boost boost-asio

boost 文档说取消的异步连接、发送和接收立即完成,取消操作的处理程序将传递 boost::asio::error::operation_aborted 错误。

我想知道取消的处理程序是否在其他(未取消的和新安排的)完成处理程序运行之前运行(并查看 operation_aborted 错误)。

这是我关心的时间表:

acceptHandler 和 readHandler 运行在同一个事件循环和同一个线程上。

  • 时间 t0 - readHandler 在 oldConnectionSocket 上运行
  • 时间 t1 - acceptHandler 运行
  • 时间 t2 - acceptHandler 调用 oldConnectionSocket.cancel
  • 时间 t3 - acceptHandler 关闭 oldConnectionSocket
  • 时间 t4 - acceptHandler 调用 newConnectionSocket.async_read(...readHandler...)
  • 时间 t5 - readHandler 被调用(从哪个上下文?)

是否可以在 t5 时在 newConnectionSocket 上下文中调用 readHandler,然后在 oldConnectionSocket 上下文中使用 operation_aborted 错误调用它?

Tan*_*ury 5

取消的操作将立即发布其处理程序以进行延迟调用。但是,io_service不保证处理程序的调用顺序。因此,io_service可以选择以任一顺序调用 ReadHandlers。目前,只有 astrand指定在某些条件下保证排序。

在完成处理程序中,如果目标是知道哪个 I/O 对象与操作相关联,则考虑构造完成处理程序,以便它具有 I/O 对象的显式句柄。这通常使用以下任何一种方法来完成:

  • 自定义函子
  • std::bind() 或者 boost::bind()
  • C++11 lambda

一种常见的习惯用法是让 I/O 对象由继承自boost::enable_shared_from_this<>. 当一个类继承自 时boost::enable_shared_from_this,它提供一个shared_from_this()成员函数,该函数返回一个有效的shared_ptr实例给this。的副本shared_ptr传递给完成处理程序,例如 lambdas 中的捕获列表或作为实例句柄传递给boost::bind()。这允许处理程序知道在其上执行操作的 I/O 对象,并使 I/O 对象的生命周期延长至至少与处理程序一样长。有关使用此方法的示例,请参阅 Boost.Asio异步 TCP 日间服务器教程。

class tcp_connection
  : public boost::enable_shared_from_this<tcp_connection>
{
public:

  // ...

  void start()
  {    
    boost::asio::async_write(socket_, ...,
        boost::bind(&tcp_connection::handle_write, shared_from_this(),
          boost::asio::placeholders::error,
          boost::asio::placeholders::bytes_transferred));
  }

  void handle_write(
    const boost::system::error_code& error,
    std::size_t bytes_transferred)
  {
    // I/O object is this->socket_.
  }

  tcp::socket socket_;
};
Run Code Online (Sandbox Code Playgroud)

另一方面,如果目标是确定一个处理程序是否在另一个之前执行,则:

  • 应用程序将需要明确管理状态
  • 尝试管理多个相关调用链可能会引入不必要的复杂性,并且通常表明需要重新检查设计
  • 自定义处理程序可用于确定处理程序执行顺序的优先级。Boost.Asio Invocation示例使用添加到优先级队列的自定义处理程序,然后在稍后的时间点执行这些处理程序。