Boost C++ 库

……世界上备受推崇且设计精良的 C++ 库项目之一。 Herb SutterAndrei AlexandrescuC++ Coding Standards

按操作取消 - Boost C++ 函数库
PrevUpHomeNext
[Note] 注意

这些类型要求和类是取消功能的底层构建块。对于大多数用例,请考虑使用更高级别的抽象,例如 experimental::make_parallel_group 或用于 awaitable逻辑运算符

I/O 对象(如套接字和计时器)通过其 closecancel 成员函数支持对象范围内的未决异步操作取消。但是,某些异步操作还支持单独、有针对性的取消。通过指定完成处理程序具有满足 CancellationSlot 类型要求的 关联取消槽 来启用此按操作取消。取消槽是用于传递取消请求的轻量级通道。

给定用户定义的 Handler 对象 h 的副本,如果异步操作支持取消,它将使用 get_associated_cancellation_slot 函数获取一个取消槽。例如

boost::asio::associated_cancellation_slot_t<Handler> s
  = boost::asio::get_associated_cancellation_slot(h);

关联取消槽必须满足 CancellationSlot 类型要求。

默认情况下,处理程序使用默认构造的 cancellation_slot,这意味着按操作取消处于禁用状态。可以通过指定嵌套类型 cancellation_slot_type 和成员函数 get_cancellation_slot() 来为特定处理程序类型自定义取消槽。

class my_handler
{
public:
  // Custom implementation of CancellationSlot type requirements.
  typedef my_cancellation_slot cancellation_slot_type;

  // Return a custom cancellation slot implementation.
  cancellation_slot_type get_cancellation_slot() const noexcept
  {
    return my_cancellation_slot(...);
  }

  void operator()() { ... }
};

在更复杂的情况下,可以直接部分特化 associated_cancellation_slot 模板。

namespace boost { namespace asio {

  template <typename CancellationSlot>
  struct associated_cancellation_slot<my_handler, CancellationSlot>
  {
    // Custom implementation of CancellationSlot type requirements.
    typedef my_cancellation_slot type;

    // Return a custom cancellation_slot implementation.
    static type get(const my_handler&,
        const CancellationSlot& a = CancellationSlot()) noexcept
    {
      return my_cancellation_slot(...);
    }
  };

} } // namespace boost::asio

为了方便起见,可以使用 bind_cancellation_slot 函数将取消槽与处理程序关联。当将取消槽与 lambda 关联时,这尤其有用。

boost::asio::async_read(my_socket, my_buffer,
    boost::asio::bind_cancellation_slot(
      my_cancellation_slot,
      [](boost::system::error_code e, std::size_t n)
      {
        ...
      }
    )
  );

Boost.Asio 以 cancellation_slot 及其对应的 cancellation_signal 的形式提供了即用型取消槽。这两个类实现了生产者(信号)和消费者(槽)接口的一对一配对。以下示例展示了其用法:

class session
  : public std::enable_shared_from_this<proxy>
{
  ...

  void do_read()
  {
    auto self = shared_from_this();
    socket_.async_read_some(
        buffer(data_),
        boost::asio::bind_cancellation_slot(
          cancel_signal_.slot(),
          [self](boost::system::error_code error, std::size_t n)
          {
            ...
          }
        )
      );
  }

  ...

  void request_cancel()
  {
    cancel_signal_.emit(boost::asio::cancellation_type::total);
  }

  ...

  boost::asio::cancellation_signal cancel_signal_;
};

一个 cancellation_signal 包含一个槽,因此一个取消信号/槽对一次最多可用于一个操作。但是,相同的槽可以重复用于后续操作。

为了支持取消,异步操作通过调用槽的 assignemplace 函数将取消处理程序安装到槽中。当发出取消信号时,将调用此处理程序。一个槽一次只能容纳一个处理程序,安装新处理程序将覆盖任何先前安装的处理程序。

发出取消信号时,调用者必须指定 取消类型。此值是一个位掩码,指示如果成功取消,取消目标必须做出何种保证。可能的位值从最弱到最强的保证是:

表 1. 取消类型

如果取消成功,则保证

此保证是最强支持保证的示例

终端

操作具有未指定副作用,并且仅关闭或销毁 I/O 对象是安全的。

消息帧协议的有状态实现,其中异步操作发送或接收完整的消息。如果在消息正文中取消,则无法向完成处理程序报告有意义的状态。

partial (部分)

操作具有明确定义的副作用,并且操作的完成处理程序指示了这些副作用。

组合操作,例如 async_readasync_write。如果在所有字节传输之前发生取消,则完成处理程序会收到迄今为止已传输的总字节数。调用者可以使用此信息启动另一个操作来传输剩余的字节。

total

操作没有通过 API 可观察到的副作用。

传输零个或非零个字节的底层系统调用。

没有副作用的等待就绪操作,即使成功也是如此。

完全缓冲的消息帧协议实现,其中存储了部分消息,以便在下一个操作中重复使用。


例如,如果应用程序逻辑要求操作具有全部或无副作用地完成,则它应仅发出 total 取消类型。如果目标操作不支持此类型,则不会发生任何取消。

此外,更强的保证始终满足较弱保证的要求。partial 保证仍然满足 terminal 保证。total 保证满足 partialterminal。这意味着当操作支持给定取消类型作为其最强保证时,它应遵守任何较弱保证的取消请求。

不应在异步操作的启动函数中发出取消请求。在操作开始之前发出的取消请求无效。同样,在完成之后发出的取消请求也无效。

发出取消信号时,线程安全规则与调用目标操作的 I/O 对象的成员函数时一样适用。对于非组合操作,这意味着可以从任何线程发出取消信号,前提是没有其他对 I/O 对象的并发调用,也没有其他并发取消信号请求。对于组合操作,必须小心确保取消请求不会与操作的中间完成处理程序并发发生。

支持的操作

请参阅各个异步操作的文档,了解其支持的取消类型(如果有)。目前,取消单个操作或组合操作的功能由以下组件支持:

  • 计时器
  • POSIX 和 Windows 上的套接字
  • POSIX 描述符
  • Windows HANDLE
  • 信号集
  • 串行端口
  • SSL 流
  • 所有 Boost.Asio 提供的组合操作,例如 async_readasync_write
  • 基于 async_compose 的组合
  • 使用 awaitable 的 C++20 协程
  • 使用 experimental::coro 的 C++20 协程
  • experimental::parallel_group 操作
  • experimental::promise
参见

CancellationSlotassociated_cancellation_slotbind_cancellation_slotcancellation_signalcancellation_slotcancellation_statecancellation_typeget_associated_cancellation_slotexperimental::parallel_groupexperimental::make_parallel_group


PrevUpHomeNext