启动提升时的例行程序::asio::io_service

Routine when starting boost::asio::io_service

本文关键字:asio io service 程序 启动      更新时间:2023-10-16

我想使用 boost asio 创建一个 http 客户端。为了有一个结构化和优化的,我研究了boost asio的例子,以了解一个好的实现应该是什么样子。

大多数情况下,我遵循 HTTP 服务器的结构,所以我有一个连接管理器,其中包含一组指向每个单独连接的指针。现在,这里最大的区别是已经在服务器的构造函数中.cpp调用了一个异步函数,即

acceptor_.async_accept(new_connection_->socket(),      boost::bind(&server::handle_accept, this,        boost::asio::p laceholders::error));

在 winmain 中.cpp io_service是通过对 server::run() 的函数调用启动

的:
io_service_.run();

在我的实现中,由于它是客户端而不是服务器,因此我想等待用户调用 send() 函数,然后再开始连接到服务器。因此,我已将所有与连接到服务器相关的函数调用移动到连接类中。当用户请求向服务器发送消息时,将调用以下内容:

resolver.async_resolve(查询,                                   boost::bind(&connection::handle_resolve, boost::ref(*this),                                               提升::ASIO::p花边持有人::错误,                                               boost::asio::p laceholders::iterator));io_service_.run();

我想在一个单独的线程中启动每个连接对象,这确实是我问题的背景。我该如何做到这一点才能获得结构化和优化的代码?

作为 HTTP Server 2 示例,我尝试设置一个io_services线程池并为它们分配工作,以便它们在停止之前不会返回。这似乎是一个好主意,因为我会让io服务一直在后台运行。因此,我从一个线程中的等效服务器.cpp启动线程池:

boost::thread t(boost::bind(&geocast::enabler::io_service_pool::run, &io_service_pool_));

但是,从我自己的试错分析来看,似乎在发出异步函数之前您无法启动io_service,这是真的吗?因为我的程序卡住了。就我而言,我只想仅在用户打算发送 POST 请求或 GET 请求时才调用async_resolve。支持我的理论;聊天客户端首先调用async_connect并具有async_read作为回调,这样它们就可以在创建客户端后立即安全地调用 io_service.run()。我不想一直从服务器读取只是为了能够启动io_service,因为这不是普通客户端的工作方式,对吧?浏览器不会在没有用户导航到网站的情况下从地球上每个可能的服务器读取......

如果我不使用示例 2 中的线程池,而是在单独的类中启动每个连接类,每个连接类都有自己的io_service,则一切正常。但是,具有简单循环例程来选择适当io_service的线程池似乎真的很有吸引力。多线程的最佳方法是什么?我只是挑剔,应该坚持一连一io_service?

我已经尝试过,作为HTTP服务器2 例如,要设置 io_services并为其分配工作 这样他们就不会回来,直到 停止。

使用异步编程时,我强烈建议按顺序使用以下设计:

  1. 单线程的单io_service
  2. 调用单个io_service的线程池
  3. 每根线io_service或其他异国情调的设计

只有在分析后当前设计被证明是瓶颈时,才应移至下一个设计。

但是,从我自己的反复试验中 分析,似乎无法开始 io_service 在您发出 异步函数,这是真的吗?

你是对的,io_service::run()文档非常清楚地说明了这一点

run() 函数块,直到所有 工作已经完成,没有 要调度的更多处理程序,或 直到io_service停止。

防止io_service::run()立即返回的正确方法是对一些处理程序进行排队,或者实例化一个io_service::work对象并将其保留在作用域中,只要您希望run()保持活动状态。

使用 ASIO

时,您将放弃对程序流的控制,交给 ASIO。如果将代码更改为使用线程池并调用 run_one() 而不是 run(),则可以共享控制权。run_one() 仅将一个 IO 作业分派给线程,因此如果 ioservice 中有多个事件,则必须多次调用 run_one()。

你有没有想过生成一个新线程作为你的老板线程,然后让你的老板线程创建一堆工作线程?你的老板线程可以调用run(),然后你的UI线程可以调用post()来调度一个新的工作单元。除了不必在 ioservice 中手动调用和调度任务外,它还使清理和关闭更加直接,因为您的 boss 线程在调用 run() 时会阻塞。