使用 boost asio 的多线程 http 处理是否需要链?

Does mulithreaded http processing with boost asio require strands?

在 boost asio documentation for strands 中它说:

Strands may be either implicit or explicit, as illustrated by the following alternative approaches:

  • ...
  • Where there is a single chain of asynchronous operations associated with a connection (e.g. in a half duplex protocol implementation like HTTP) there is no possibility of concurrent execution of the handlers. This is an implicit strand.
  • ...

不过,在boost beast的example for a multithreaded asynchronous http server the boost::asio::ip::tcp::acceptor as well as each boost::asio::ip::tcp::socket get their own strand explicitly (see line 373 and 425)。据我所知,这不是必需的,因为所有这些对象只会按顺序 registered/running CompletionHandlers 访问。准确地说,其中一个的新异步操作objects 仅在同一对象上注册的 CompletionHandler 末尾注册,使得任何对象都可以在 单个异步操作链

中使用

因此,我假设 - 尽管有多个线程 运行 并发 - 在此示例中可以一起省略链,并且 io_context 可用于直接调度任何异步操作。那是对的吗?如果不是,我缺少哪些同步问题?我是否误解了上面文档中的声明?


¹:当然,可以同时使用两个套接字或一个套接字和接受器,但是由于使用了 multiple stands 这不会被阻止在示例中。

²:不可否认,在当前CompletionHandler末尾注册的CompletionHandler可能会在另一个线程之前当前处理程序实际完成之前启动,一世。 e. returns。但我会假设这不是冒同步问题风险的情况。如果我错了,请纠正我。

如果异步操作链创建一个逻辑链,那么您通常不需要显式链。

此外,如果执行上下文仅 run/polled 来自单个线程,则所有异步操作都将在该隐式链上有效。

示例不止一个目的。

  • 一方面。他们显然保持简单。自然会有最少的线程数或简单的操作链。

  • 然而,这导致 over-simplified 与现实生活关系不大的示例。

  • 因此,即使不是绝对所必需的,样本也经常显示良好的实践或高级模式。有时(通常是 IME)这甚至会被明确注释。例如。在你非常链接的例子中 L277:

     // We need to be executing within a strand to perform async operations
     // on the I/O objects in this session. Although not strictly necessary
     // for single-threaded contexts, this example code is written to be
     // thread-safe by default.
     net::dispatch(stream_.get_executor(),
                   beast::bind_front_handler(
                       &session::do_read,
                       shared_from_this()));
    

励志例子

这让人们可以解决他们的下一个 non-trivial 任务。例如,假设您想将 stop() 添加到链接示例中的 listener class。没有绳索就无法安全地做到这一点。您需要“注入”对 acceptor.cancel() 内部 逻辑“链”的调用,即包含 async_accept 的异步操作链。但是你不能,因为 async_accept 在“逻辑上阻塞”了那个链。所以你实际上确实需要 post 到一个明确的链:

void stop() {
  post(acceptor_.get_executor(), [this] { acceptor_.cancel(); });
}