异步操作的此属性的名称是什么。 (提升asio相关)

时间:2012-12-30 08:37:21

标签: asynchronous boost-asio

该属性可以这样描述:如果操作被取消,它的处理程序将保证执行时出错

例如,boost::asio::deadline_timer没有Remarks section of documentation for deadline_timer::cancel function中所述的此属性。所以有可能即使一个取消对定时器的等待操作,它的回调也会在没有错误的情况下执行。

另一方面,该属性适用于asio套接字(至少我希望如此:),因为文档中没有这样的评论。)

编辑:一个伪代码,证明在截止时间计时器中缺少此属性:

1# User calls timer.async_wait with a handler H which is to be
   executed when the action finishes.
2# Time passes.
3# Timeout has been reached, asio internally inserts the handler H into
   a queue for later execution, but with error code indicating success.
   User is unaware of when this step takes place.
4# User calls cancel on the timer, thus would expect the handler to be
   executed with an error code indicating failure.
5# Asio takes the handler H from the queue and executes it with error
   code indicating success as set in the step #3.

通过在步骤#4中设置一个布尔标志然后在步骤#5中检查它来解决这个问题很容易,所以这不是问题。

1 个答案:

答案 0 :(得分:4)

documentationNetworking Library Proposal for TR2都没有定义异步操作的术语,取消时保证错误。但是,所有异步操作(包括boost::asio::deadline_timer::async_wait())都会出现此行为。处理程序的设计使它们始终提供相关操作的状态。如果没有这种保证,当取消或多次操作发生时,开发人员将处于处理程序中的未知状态。

取消仅适用于尚未进行的操作。我认为文档仅针对计时器类强调了这一点,因为异步操作的可见性不同。 I / O对象上的操作具有很高的可见性。例如,可以嗅探网络以观察套接字上的异步写操作。另一方面,计时器'操作可见度低。等待操作的机制是Boost.Asio中的实现细节,并且API不提供执行操作的外部监视的能力。

在伪代码中,已达到超时,表示异步等待操作已完成。因此,由于行动已经发生,因此无法再取消。因此,不会使用boost::asio::error::operation_aborted错误调用处理程序。至关重要的是要理解取消是一种行动,而不是一种状态变化。因此,无法查询计时器以查看是否已发生取消。此外,如果用户希望取消修改处理程序的错误代码,那么用户可能会因为异步操作的启动,完成和通知之间的时间间隔而导致继承复杂性丢失。


以下所有内容对实施细节都非常具体。在这种情况下,在系统上使用boost::asio::ip::tcp::socket::async_receive在套接字上发生异步读取,其中Boost.Asio将使用epoll作为其反应器。

初始化

  1. 创建套接字对象时,其服务reactive_socket_service_base通知反应堆初始化任务(reactor::init_task())。
  2. 然后,reactor将通知io_service初始化任务。这会导致将标记操作添加到io_service的操作队列中。
  3. 当套接字打开时带有有效的文件描述符时,会向reactor注册与文件描述符(descriptor_data)关联的数据结构。这个结构有自己的操作队列,实际上它被视为一个操作本身。
  4. reactor从descriptor_data中提取文件描述符,并将其添加到文件描述符列表中,以便在反应器内进行观察。
  5. 启动异步读取操作

    1. boost::asio::detail::reactive_socket_service_base::async_receive()创建一个boost::asio::detail::reactive_socket_recv_op对象。该对象是一个操作对象。它的perform()成员函数将尝试从套接字读取数据,其complete()成员函数将调用用户的完成处理程序。
    2. 使用读取操作调用
    3. boost::asio::detail::reactive_socket_service_base::start_op(),该操作将调用reactor::start_op()
    4. reactor获取套接字的descriptor_data,锁定特定于描述符的互斥锁,将操作推送到特定于描述符的操作队列,通知io_service有工作,然后解锁互斥锁。
    5. 套接字获取数据,异步读取操作的完成开始

      1. io_service::run*()被调用。
      2. io_service只检查其操作队列是否准备好运行任何操作。在这种情况下,初始化期间创建的标记操作位于队列中。该操作被标识为标记,表示存在反应堆,并调用reactor::run()
      3. 反应堆将在epoll_wait上阻止。当套接字的文件描述符具有活动时,则识别该事件。从事件中提取descriptor_data,并将其推送到调用者的操作队列,因为descriptor_data是一个操作。
      4. 然后将传回给调用者的操作添加到io_service的操作队列中,该队列现在包含descriptor_data操作和原始标记操作。
      5. descriptor_data队列中弹出io_service操作,并调用complete()成员函数,导致epoll_reactor::descriptor_state::do_complete运行。
      6. do_complete调用epoll_reactor::descriptor_state::perform_io,其中descriptor_data操作队列中的操作被迭代,并调用perform()。这包括在异步操作启动期间推入队列的boost::asio::detail::reactive_socket_recv_op操作。
      7. 读取操作的perform()成员函数将调用socket_ops::non_blocking_recv(),其中尝试从套接字读取实际数据。传输的错误代码和字节存储在操作中。
      8. 该操作已从descriptor_data的操作队列中删除,并通过task_io_service::post_deferred_completion添加到io_service
      9. 异步读取操作的通知

        1. io_service现在队列中有两个操作:完成的读操作和标记操作。 reactor在其队列中没有任何操作。
        2. 读取操作最终迭代到,并且其complete()成员函数调用。在reactive_socket_recv_op::do_complete内,用户处理程序调用错误代码和传输的字节。
        3. 取消

          1. boost::asio::detail::reactive_socket_service_base::cancel()使用reactor::cancel_ops调用descriptor_data
          2. epoll_reactor::cancel_ops()遍历descriptor_data的操作队列。每个操作都从descriptor_data的操作队列中弹出,其错误代码设置为boost::asio::error::operation_aborted,然后添加到io_service的操作队列。
          3. 因此,取消仅通过从descriptor_data的操作队列中删除它们来影响尚未调用的操作。如果已调用某个操作,则该操作已从descriptor_data的操作队列中删除,并添加到io_service操作队列中。