我在这里看到过类似问题的文章,但是我的问题有所不同,没有答案可以帮助我解决这个问题。我有一个基于此boost http/server3示例的多线程boost asio异步HTTP服务器。我正在使用boost 1.64.0,并且正在Windows 10 64位上对其进行测试。在VS 2015 64上编译
我有一个线程池,该线程池调用 io_service.run()。服务器的基本思想是我有一个线程池,所有线程都在侦听传入的请求。当我使用单线程时,一切正常。网页加载没有问题。但是问题出在我使用2个以上线程时。 如果一个线程尚未完成其工作(例如,忙于某个正在处理数据库的POST请求),接收器套接字(随机)将不接受某些请求,并等待直到第一个线程完成(请求显示为在Firefox中的“网络”标签中待处理)。有时页面加载没有问题,但大多数情况下页面会停顿直到第一个线程完成工作为止。有谁知道可能导致此问题的原因?
我尝试使用BOOST_ASIO_ENABLE_HANDLER_TRACKING定义来跟踪问题,直到问题停顿为止
@asio|1555450197.805179|3404*3407|strand@0000024EAAB649E0.dispatch
@asio|1555450197.805179|>3407|
@asio|1555450197.805179|3407*3408|socket@0000024EAAD400A0.async_send
@asio|1555450197.806177|<3407|
@asio|1555450197.806177|<3404|
@asio|1555450197.806177|>3405|ec=system:0
@asio|1555450197.806177|3405*3409|socket@0000024EAAB76D20.async_receive
accepting request
@asio|1555450197.806177|3405*3410|socket@0000024EA92D9CF0.async_accept
@asio|1555450197.806177|<3405|
@asio|1555450197.806177|>3408|ec=system:0,bytes_transferred=24530
@asio|1555450197.806177|3408*3411|strand@0000024EAAB649E0.dispatch
@asio|1555450197.806177|>3411|
@asio|1555450197.806177|<3411|
@asio|1555450197.806177|0|socket@0000024EAAD400A0.close
@asio|1555450197.806177|<3408|
@asio|1555450197.806177|>3409|ec=system:0,bytes_transferred=375
@asio|1555450197.807174|3409*3412|strand@0000024EAAB64580.dispatch
@asio|1555450197.807174|>3412|
@asio|1555450197.807174|3412*3413|socket@0000024EAAB76D20.async_send
@asio|1555450197.807174|<3412|
@asio|1555450197.807174|<3409|
@asio|1555450197.807174|>3413|ec=system:0,bytes_transferred=26952
@asio|1555450197.807174|3413*3414|strand@0000024EAAB64580.dispatch
@asio|1555450197.807174|>3414|
@asio|1555450197.807174|<3414|
@asio|1555450197.807174|0|socket@0000024EAAB76D20.close
@asio|1555450197.808173|<3413|
这是我的构造函数
boost::asio::ip::tcp::resolver resolver(io_service_);
boost::asio::ip::tcp::resolver::query query(address, port);
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
acceptor_.open(endpoint.protocol());
acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
acceptor_.bind(endpoint);
acceptor_.listen();
boost::system::error_code error;
handle_accept(error);
我的句柄接受功能
void server::handle_accept(const boost::system::error_code& e)
{
if (!e)
{
new_connection_.reset(new connection(io_service_, *request_handler_, max_cont_lenght, min_upload_speed));
acceptor_.async_accept(new_connection_->socket(), [this](boost::system::error_code error)
{
this->start_accept(error);
});
}
}
启动接受功能
void server::start_accept(const boost::system::error_code& e)
{
if (!e)
{
new_connection_->start();
}
handle_accept(e);
}
服务器运行功能
void server::run()
{
// Create a pool of threads to run all of the io_services.
for (std::size_t i = 0; i < thread_pool_size_; ++i)
{
std::shared_ptr<boost::thread> thread(new boost::thread(
[this](){
this->io_service_run();
}
));
threads.push_back(thread);
}
// Wait for all threads in the pool to exit.
for (std::size_t i = 0; i < threads.size(); ++i)
{
threads[i]->join();
}
}
答案 0 :(得分:0)
通过简单的暴力破解,我弄清了这个问题的原因。显然,这不是接受者的问题,问题出在连接类中。在同一 http/server3示例中。仅当您将回调函数包装成一束时,这种情况才会发生。
socket_.async_read_some(boost::asio::buffer(buffer_),
strand_.wrap(
boost::bind(&connection::handle_read, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)));
有趣的是,handle_read函数中使用的同一链似乎没有引起此问题。根据文档,http / server3实现是正确的
显式链是io_service :: strand的实例。所有事件处理程序功能对象都需要使用io_service :: strand :: wrap()进行包装,或者通过io_service :: strand对象进行发布/分发。 对于组合式异步操作(例如async_read()或async_read_until()),如果完成处理程序经过一个链,则所有中间处理程序也应经过同一链。为了确保线程安全地访问在调用方和组合操作之间共享的任何对象
但是从连接start()函数中删除strand_.wrap似乎可以解决此问题。不知道这是Boost 1.64中的错误还是我丢失了某些东西。