Boost C++ 库

…在世界上最受尊敬、设计最精良的 C++ 库项目之一。 Herb SutterAndrei Alexandrescu, C++ 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
另请参阅

CancellationSlot, associated_cancellation_slot, bind_cancellation_slot, cancellation_signal, cancellation_slot, cancellation_state, cancellation_type, get_associated_cancellation_slot, experimental::parallel_group, experimental::make_parallel_group


PrevUpHomeNext